2008-05-16 19:30:57 +04:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2012-03-02 19:47:34 +04:00
|
|
|
#include "config.h"
|
|
|
|
|
2008-05-16 19:30:57 +04:00
|
|
|
#ifndef _GNU_SOURCE
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2013-07-31 16:50:44 +04:00
|
|
|
#include <inttypes.h>
|
2011-04-06 18:43:04 +04:00
|
|
|
#include <time.h>
|
2012-08-17 17:48:56 +04:00
|
|
|
#include <limits.h>
|
2008-05-16 19:30:57 +04:00
|
|
|
|
|
|
|
#include "csync_private.h"
|
|
|
|
#include "csync_propagate.h"
|
2013-02-27 15:34:42 +04:00
|
|
|
#include "csync_statedb.h"
|
2013-03-23 00:04:09 +04:00
|
|
|
#include "vio/csync_vio_local.h"
|
2008-05-16 19:30:57 +04:00
|
|
|
#include "vio/csync_vio.h"
|
2012-08-17 17:48:56 +04:00
|
|
|
#include "c_jhash.h"
|
2008-05-16 19:30:57 +04:00
|
|
|
|
|
|
|
#define CSYNC_LOG_CATEGORY_NAME "csync.propagator"
|
|
|
|
#include "csync_log.h"
|
2011-04-06 18:43:04 +04:00
|
|
|
#include "csync_util.h"
|
2013-03-11 22:02:18 +04:00
|
|
|
#include "csync_misc.h"
|
2013-01-04 23:45:10 +04:00
|
|
|
#include "csync_rename.h"
|
|
|
|
|
|
|
|
static int _csync_build_remote_uri(CSYNC *ctx, char **dst, const char *path) {
|
|
|
|
char *tmp = csync_rename_adjust_path(ctx, path);
|
|
|
|
int ret = asprintf(dst, "%s/%s", ctx->remote.uri, tmp);
|
|
|
|
SAFE_FREE(tmp);
|
|
|
|
return ret;
|
|
|
|
}
|
2008-05-16 19:30:57 +04:00
|
|
|
|
2008-05-20 15:56:43 +04:00
|
|
|
static int _csync_cleanup_cmp(const void *a, const void *b) {
|
|
|
|
csync_file_stat_t *st_a, *st_b;
|
|
|
|
|
2013-04-22 12:22:20 +04:00
|
|
|
st_a = *((csync_file_stat_t **) a);
|
|
|
|
st_b = *((csync_file_stat_t **) b);
|
2008-05-20 15:56:43 +04:00
|
|
|
|
|
|
|
return strcmp(st_a->path, st_b->path);
|
|
|
|
}
|
|
|
|
|
2013-03-28 16:04:13 +04:00
|
|
|
static void _csync_file_stat_set_error(csync_file_stat_t *st, const char *error)
|
|
|
|
{
|
|
|
|
st->instruction = CSYNC_INSTRUCTION_ERROR;
|
2013-04-03 12:53:20 +04:00
|
|
|
if (st->error_string || !error)
|
2013-03-28 16:04:13 +04:00
|
|
|
return; // do not override first error.
|
2013-04-03 12:53:20 +04:00
|
|
|
st->error_string = c_strdup(error);
|
2013-03-28 16:04:13 +04:00
|
|
|
}
|
|
|
|
|
2013-07-15 12:46:33 +04:00
|
|
|
/* Recursively mark the parent flder as an error */
|
2013-07-31 15:12:10 +04:00
|
|
|
static void _csync_report_parent_error(CSYNC *ctx, csync_file_stat_t *st) {
|
2013-07-15 12:46:33 +04:00
|
|
|
const char *dir = NULL;
|
|
|
|
uint64_t h;
|
|
|
|
c_rbnode_t* node;
|
|
|
|
|
|
|
|
dir = c_dirname(st->path);
|
|
|
|
if (!dir) return;
|
|
|
|
|
|
|
|
h = c_jhash64((uint8_t *) dir, strlen(dir), 0);
|
|
|
|
node = c_rbtree_find(ctx->local.tree, &h);
|
|
|
|
|
|
|
|
if (!node) {
|
|
|
|
/* Not in the local tree, mark the remote tree as an error then */
|
|
|
|
node = c_rbtree_find(ctx->remote.tree, &h);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node) {
|
|
|
|
st = node->data;
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,
|
|
|
|
"Mark parent directoy `%s` as an error",
|
|
|
|
dir);
|
|
|
|
|
|
|
|
_csync_file_stat_set_error(st, "Error within the directory");
|
|
|
|
_csync_report_parent_error(ctx, st);
|
|
|
|
}
|
|
|
|
|
|
|
|
SAFE_FREE(dir);
|
|
|
|
}
|
|
|
|
|
2013-02-27 15:34:42 +04:00
|
|
|
/* Record the error in the ctx->progress
|
|
|
|
pi may be a previous csync_progressinfo_t from the database.
|
|
|
|
If pi is NULL, a new one is created, else it is re-used
|
|
|
|
*/
|
2013-03-28 16:04:13 +04:00
|
|
|
static void _csync_record_error(CSYNC *ctx, csync_file_stat_t *st, csync_progressinfo_t *pi)
|
|
|
|
{
|
|
|
|
_csync_file_stat_set_error(st, csync_get_error_string(ctx));
|
2013-07-15 12:46:33 +04:00
|
|
|
_csync_report_parent_error(ctx, st);
|
2013-02-27 15:34:42 +04:00
|
|
|
if (pi) {
|
|
|
|
pi->error++;
|
2013-03-28 16:21:55 +04:00
|
|
|
SAFE_FREE(pi->error_string);
|
2013-02-27 15:34:42 +04:00
|
|
|
} else {
|
|
|
|
pi = c_malloc(sizeof(csync_progressinfo_t));
|
|
|
|
pi->chunk = 0;
|
2013-03-11 22:02:18 +04:00
|
|
|
pi->transferId = 0;
|
2013-02-27 15:34:42 +04:00
|
|
|
pi->tmpfile = NULL;
|
|
|
|
pi->md5 = st->md5 ? c_strdup(st->md5) : NULL;
|
|
|
|
pi->modtime = st->modtime;
|
|
|
|
pi->phash = st->phash;
|
|
|
|
pi->error = 1;
|
|
|
|
}
|
2013-03-28 16:21:55 +04:00
|
|
|
pi->error_string = st->error_string ? c_strdup(st->error_string) : NULL;
|
2013-05-06 19:14:17 +04:00
|
|
|
pi->next = ctx->progress_info;
|
|
|
|
ctx->progress_info = pi;
|
2013-02-27 15:34:42 +04:00
|
|
|
}
|
|
|
|
|
2012-06-22 17:32:04 +04:00
|
|
|
static bool _push_to_tmp_first(CSYNC *ctx)
|
|
|
|
{
|
2012-12-04 18:03:49 +04:00
|
|
|
if( !ctx ) return true;
|
2012-10-27 21:27:14 +04:00
|
|
|
if( ctx->current == REMOTE_REPLICA ) return true; /* Always push to tmp for destination local file system */
|
2012-06-25 15:03:27 +04:00
|
|
|
|
|
|
|
/* If destination is the remote replica check if the switch is set. */
|
2012-07-04 15:56:24 +04:00
|
|
|
if( !ctx->module.capabilities.atomar_copy_support ) return true;
|
2012-06-25 15:03:27 +04:00
|
|
|
|
2012-06-22 17:32:04 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-08-02 17:02:41 +04:00
|
|
|
static void _notify_progress(CSYNC *ctx, const char *file, int64_t filesize, enum csync_notify_type_e kind)
|
2013-07-25 17:36:46 +04:00
|
|
|
{
|
|
|
|
if (ctx == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (ctx->callbacks.progress_cb) {
|
|
|
|
CSYNC_PROGRESS progress;
|
|
|
|
progress.kind = kind;
|
|
|
|
progress.path = file;
|
|
|
|
progress.curr_bytes = 0;
|
2013-08-02 17:02:41 +04:00
|
|
|
progress.file_size = filesize;
|
2013-07-25 17:36:46 +04:00
|
|
|
progress.overall_transmission_size = ctx->overall_progress.byte_sum;
|
|
|
|
progress.current_overall_bytes = ctx->overall_progress.byte_current;
|
|
|
|
progress.overall_file_count = ctx->overall_progress.file_count;
|
|
|
|
progress.current_file_no = ctx->overall_progress.current_file_no;
|
|
|
|
|
|
|
|
ctx->callbacks.progress_cb(&progress, ctx->callbacks.userdata);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-04 18:03:49 +04:00
|
|
|
static bool _use_fd_based_push(CSYNC *ctx)
|
|
|
|
{
|
|
|
|
if(!ctx) return false;
|
|
|
|
|
|
|
|
if( ctx->module.capabilities.use_send_file_to_propagate ) return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-08-17 17:48:56 +04:00
|
|
|
static const char*_get_md5( CSYNC *ctx, const char *path ) {
|
|
|
|
const char *md5 = NULL;
|
|
|
|
char *buf = NULL;
|
2012-08-23 18:40:36 +04:00
|
|
|
|
2012-08-17 17:48:56 +04:00
|
|
|
/* Always use the remote uri path, local does not have Ids. */
|
|
|
|
if (asprintf(&buf, "%s/%s", ctx->remote.uri, path) < 0) {
|
|
|
|
return 0;
|
2012-08-23 18:40:36 +04:00
|
|
|
}
|
2012-08-17 17:48:56 +04:00
|
|
|
|
|
|
|
md5 = csync_vio_file_id(ctx, buf);
|
|
|
|
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "MD5 for %s: %s", buf, md5 ? md5 : "<null>");
|
|
|
|
SAFE_FREE(buf);
|
2012-08-14 17:31:52 +04:00
|
|
|
return md5;
|
2012-08-23 18:40:36 +04:00
|
|
|
}
|
|
|
|
|
2008-05-20 16:01:04 +04:00
|
|
|
static int _csync_push_file(CSYNC *ctx, csync_file_stat_t *st) {
|
2008-05-19 13:16:51 +04:00
|
|
|
enum csync_replica_e srep = -1;
|
|
|
|
enum csync_replica_e drep = -1;
|
|
|
|
enum csync_replica_e rep_bak = -1;
|
2008-05-16 19:30:57 +04:00
|
|
|
|
|
|
|
char *suri = NULL;
|
|
|
|
char *duri = NULL;
|
|
|
|
char *turi = NULL;
|
|
|
|
char *tdir = NULL;
|
2013-01-09 20:20:48 +04:00
|
|
|
char *auri = NULL;
|
2012-08-17 17:48:56 +04:00
|
|
|
const char *tmd5 = NULL;
|
2012-11-29 16:38:28 +04:00
|
|
|
char *prev_tdir = NULL;
|
2008-05-16 19:30:57 +04:00
|
|
|
|
|
|
|
csync_vio_handle_t *sfp = NULL;
|
|
|
|
csync_vio_handle_t *dfp = NULL;
|
|
|
|
|
|
|
|
csync_vio_file_stat_t *tstat = NULL;
|
2013-04-09 18:43:21 +04:00
|
|
|
csync_vio_file_stat_t *vst = NULL;
|
2008-05-16 19:30:57 +04:00
|
|
|
|
2008-07-18 13:35:02 +04:00
|
|
|
char errbuf[256] = {0};
|
2008-05-16 19:30:57 +04:00
|
|
|
char buf[MAX_XFER_BUF_SIZE] = {0};
|
|
|
|
ssize_t bread = 0;
|
|
|
|
ssize_t bwritten = 0;
|
|
|
|
struct timeval times[2];
|
|
|
|
|
|
|
|
int rc = -1;
|
2008-06-09 18:43:57 +04:00
|
|
|
int count = 0;
|
2008-06-16 18:40:25 +04:00
|
|
|
int flags = 0;
|
2013-04-09 18:43:21 +04:00
|
|
|
bool do_pre_copy_stat = false; /* do an additional stat before actually copying */
|
2008-05-16 19:30:57 +04:00
|
|
|
|
2013-03-11 22:02:18 +04:00
|
|
|
csync_hbf_info_t hbf_info = { 0, 0 };
|
2013-04-04 14:58:29 +04:00
|
|
|
csync_progressinfo_t *progress_info = NULL;
|
2013-07-25 17:36:46 +04:00
|
|
|
|
|
|
|
enum csync_notify_type_e notify_start_kind = CSYNC_NOTIFY_START_UPLOAD;
|
|
|
|
enum csync_notify_type_e notify_end_kind = CSYNC_NOTIFY_FINISHED_UPLOAD;
|
|
|
|
|
|
|
|
|
2013-04-04 14:58:29 +04:00
|
|
|
/* Check if there is progress info stored in the database for this file */
|
|
|
|
progress_info = csync_statedb_get_progressinfo(ctx, st->phash, st->modtime, st->md5);
|
2013-06-07 16:58:38 +04:00
|
|
|
rep_bak = ctx->replica;
|
|
|
|
|
2013-06-18 20:15:43 +04:00
|
|
|
#ifdef BLACKLIST_ON_ERROR
|
2013-04-04 14:58:29 +04:00
|
|
|
if (progress_info && progress_info->error > 3) {
|
2013-06-18 20:15:43 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"'%s' was blacklisted after %d errors: %s",
|
|
|
|
st->path, progress_info->error, progress_info->error_string);
|
2013-02-27 15:34:42 +04:00
|
|
|
rc = 1;
|
|
|
|
goto out;
|
|
|
|
}
|
2013-06-18 20:15:43 +04:00
|
|
|
#endif
|
2013-04-04 14:58:29 +04:00
|
|
|
|
|
|
|
if (progress_info) {
|
2013-03-11 22:02:18 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,
|
|
|
|
"continuation: %d %d",
|
2013-04-04 14:58:29 +04:00
|
|
|
progress_info->chunk, progress_info->transferId );
|
|
|
|
hbf_info.start_id = progress_info->chunk;
|
|
|
|
hbf_info.transfer_id = progress_info->transferId;
|
2013-03-11 22:02:18 +04:00
|
|
|
}
|
2013-02-27 15:34:42 +04:00
|
|
|
|
2008-05-16 19:30:57 +04:00
|
|
|
|
2013-01-09 20:20:48 +04:00
|
|
|
auri = csync_rename_adjust_path(ctx, st->path);
|
|
|
|
|
2008-05-16 19:30:57 +04:00
|
|
|
switch (ctx->current) {
|
|
|
|
case LOCAL_REPLICA:
|
|
|
|
srep = ctx->local.type;
|
|
|
|
drep = ctx->remote.type;
|
2013-01-09 20:20:48 +04:00
|
|
|
if (asprintf(&suri, "%s/%s", ctx->local.uri, auri) < 0) {
|
2008-05-16 19:30:57 +04:00
|
|
|
rc = -1;
|
|
|
|
goto out;
|
|
|
|
}
|
2013-01-04 23:45:10 +04:00
|
|
|
if (_csync_build_remote_uri(ctx, &duri, st->path) < 0) {
|
|
|
|
rc = -1;
|
2008-05-16 19:30:57 +04:00
|
|
|
goto out;
|
|
|
|
}
|
2013-04-09 18:43:21 +04:00
|
|
|
do_pre_copy_stat = true;
|
2008-05-16 19:30:57 +04:00
|
|
|
break;
|
2012-10-19 16:23:20 +04:00
|
|
|
case REMOTE_REPLICA:
|
2008-05-16 19:30:57 +04:00
|
|
|
srep = ctx->remote.type;
|
|
|
|
drep = ctx->local.type;
|
2013-07-25 17:36:46 +04:00
|
|
|
notify_start_kind = CSYNC_NOTIFY_START_DOWNLOAD;
|
|
|
|
notify_end_kind = CSYNC_NOTIFY_FINISHED_DOWNLOAD;
|
|
|
|
|
2013-01-04 23:45:10 +04:00
|
|
|
if (_csync_build_remote_uri(ctx, &suri, st->path) < 0) {
|
2008-05-16 19:30:57 +04:00
|
|
|
rc = -1;
|
|
|
|
goto out;
|
|
|
|
}
|
2013-01-09 20:20:48 +04:00
|
|
|
if (asprintf(&duri, "%s/%s", ctx->local.uri, auri) < 0) {
|
2008-05-16 19:30:57 +04:00
|
|
|
rc = -1;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-07-26 15:43:02 +04:00
|
|
|
/* Increment by one as its started now. */
|
|
|
|
ctx->overall_progress.current_file_no++;
|
2013-08-02 17:02:41 +04:00
|
|
|
_notify_progress(ctx, duri, 0, notify_start_kind);
|
2013-07-25 17:36:46 +04:00
|
|
|
|
2013-04-09 18:43:21 +04:00
|
|
|
/* Check if the file is still untouched since the update run. */
|
|
|
|
if (do_pre_copy_stat) {
|
|
|
|
vst = csync_vio_file_stat_new();
|
|
|
|
if (csync_vio_stat(ctx, suri, vst) < 0) {
|
|
|
|
/* Pre copy stat failed */
|
|
|
|
rc = 1;
|
|
|
|
goto out;
|
|
|
|
} else {
|
|
|
|
/* Pre copy stat succeeded */
|
|
|
|
if (st->modtime != vst->mtime ||
|
|
|
|
st->size != vst->size) {
|
|
|
|
/* The size or modtime has changed. Skip this file copy for now. */
|
|
|
|
rc = 1; /* soft problem */
|
2013-08-18 20:15:05 +04:00
|
|
|
SAFE_FREE(st->error_string);
|
|
|
|
st->error_string = c_strdup("File was updated meantime, publish next time.");
|
2013-04-09 18:43:21 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
|
2013-08-18 20:15:05 +04:00
|
|
|
"Source file %s has changed since update run, SKIP it for now.", suri);
|
2013-04-09 18:43:21 +04:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
csync_vio_file_stat_destroy(vst);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-16 19:30:57 +04:00
|
|
|
/* Open the source file */
|
|
|
|
ctx->replica = srep;
|
2008-06-16 18:40:25 +04:00
|
|
|
flags = O_RDONLY|O_NOFOLLOW;
|
2012-10-15 23:27:17 +04:00
|
|
|
#ifdef O_NOATIME
|
2008-06-16 19:48:48 +04:00
|
|
|
/* O_NOATIME can only be set by the owner of the file or the superuser */
|
2008-11-13 16:08:26 +03:00
|
|
|
if (st->uid == ctx->pwd.uid || ctx->pwd.euid == 0) {
|
2008-06-16 18:40:25 +04:00
|
|
|
flags |= O_NOATIME;
|
|
|
|
}
|
2012-07-19 23:11:35 +04:00
|
|
|
#endif
|
2008-11-12 23:14:35 +03:00
|
|
|
sfp = csync_vio_open(ctx, suri, flags, 0);
|
2008-05-16 19:30:57 +04:00
|
|
|
if (sfp == NULL) {
|
2008-05-19 18:29:01 +04:00
|
|
|
if (errno == ENOMEM) {
|
|
|
|
rc = -1;
|
|
|
|
} else {
|
|
|
|
rc = 1;
|
|
|
|
}
|
2012-03-07 18:42:07 +04:00
|
|
|
|
2013-08-02 17:19:41 +04:00
|
|
|
C_STRERROR(errno, errbuf, sizeof(errbuf));
|
2008-07-18 13:35:02 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"file: %s, command: open(O_RDONLY), error: %s",
|
2012-03-07 18:42:07 +04:00
|
|
|
suri, errbuf );
|
|
|
|
|
2008-05-16 19:30:57 +04:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2012-06-22 17:32:04 +04:00
|
|
|
if (_push_to_tmp_first(ctx)) {
|
2013-04-04 14:58:29 +04:00
|
|
|
if (progress_info && progress_info->tmpfile && progress_info->tmpfile[0] && _push_to_tmp_first(ctx)) {
|
|
|
|
turi = c_strdup(progress_info->tmpfile);
|
2013-03-02 18:02:27 +04:00
|
|
|
/* Try to see if we can resume. */
|
|
|
|
ctx->replica = drep;
|
2013-07-16 11:19:36 +04:00
|
|
|
dfp = csync_vio_open(ctx, turi, O_WRONLY|O_APPEND|O_NOCTTY, 0);
|
2013-03-02 18:02:27 +04:00
|
|
|
if (dfp) {
|
|
|
|
goto start_fd_based;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-22 17:32:04 +04:00
|
|
|
/* create the temporary file name */
|
2013-04-04 14:57:44 +04:00
|
|
|
turi = c_tmpname(duri);
|
2012-06-22 17:32:04 +04:00
|
|
|
|
2013-04-04 14:57:44 +04:00
|
|
|
if (!turi) {
|
2012-06-22 17:32:04 +04:00
|
|
|
rc = -1;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* write to the target file directly as the HTTP server does it atomically */
|
|
|
|
if (asprintf(&turi, "%s", duri) < 0) {
|
|
|
|
rc = -1;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,
|
2012-06-25 15:03:27 +04:00
|
|
|
"Remote repository atomar push enabled for %s (%d).", turi, ctx->current);
|
2008-11-13 17:11:02 +03:00
|
|
|
|
|
|
|
}
|
2008-06-05 14:02:37 +04:00
|
|
|
|
2008-06-06 12:28:53 +04:00
|
|
|
/* Create the destination file */
|
2008-05-16 19:30:57 +04:00
|
|
|
ctx->replica = drep;
|
2008-09-05 15:28:05 +04:00
|
|
|
while ((dfp = csync_vio_open(ctx, turi, O_CREAT|O_EXCL|O_WRONLY|O_NOCTTY,
|
|
|
|
C_FILE_MODE)) == NULL) {
|
2012-06-22 17:32:04 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,
|
|
|
|
"file: %s, command: open(O_CREAT), error: %d",
|
|
|
|
duri, errno);
|
|
|
|
|
2008-06-04 20:19:14 +04:00
|
|
|
switch (errno) {
|
2008-06-06 12:27:15 +04:00
|
|
|
case EEXIST:
|
2008-06-06 15:23:42 +04:00
|
|
|
if (count++ > 10) {
|
2008-09-05 15:28:05 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"file: %s, command: open(O_CREAT), error: max count exceeded",
|
|
|
|
duri);
|
2008-06-06 15:23:42 +04:00
|
|
|
rc = 1;
|
|
|
|
goto out;
|
|
|
|
}
|
2012-06-22 17:32:04 +04:00
|
|
|
if(_push_to_tmp_first(ctx)) {
|
2013-04-04 14:57:44 +04:00
|
|
|
SAFE_FREE(turi);
|
|
|
|
turi = c_tmpname(duri);
|
|
|
|
if (!turi) {
|
2012-06-22 17:32:04 +04:00
|
|
|
rc = -1;
|
|
|
|
goto out;
|
|
|
|
}
|
2008-11-13 17:11:02 +03:00
|
|
|
}
|
2008-06-06 12:27:15 +04:00
|
|
|
break;
|
2008-06-04 20:19:14 +04:00
|
|
|
case ENOENT:
|
2008-06-06 12:28:53 +04:00
|
|
|
/* get the directory name */
|
2012-12-15 02:05:17 +04:00
|
|
|
SAFE_FREE(tdir);
|
2008-06-06 12:28:53 +04:00
|
|
|
tdir = c_dirname(turi);
|
|
|
|
if (tdir == NULL) {
|
|
|
|
rc = -1;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2012-11-21 17:53:54 +04:00
|
|
|
if( prev_tdir && c_streq(tdir, prev_tdir) ) {
|
|
|
|
/* we're looping */
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN,
|
|
|
|
"dir: %s, loop in mkdir detected!", tdir);
|
2012-12-19 18:08:32 +04:00
|
|
|
rc = 1;
|
2012-11-21 17:53:54 +04:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
SAFE_FREE(prev_tdir);
|
|
|
|
prev_tdir = c_strdup(tdir);
|
|
|
|
|
2008-06-24 20:02:00 +04:00
|
|
|
if (csync_vio_mkdirs(ctx, tdir, C_DIR_MODE) < 0) {
|
2013-08-02 17:19:41 +04:00
|
|
|
C_STRERROR(errno, errbuf, sizeof(errbuf));
|
2008-07-18 13:35:02 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN,
|
|
|
|
"dir: %s, command: mkdirs, error: %s",
|
2012-03-07 18:42:07 +04:00
|
|
|
tdir, errbuf);
|
2008-06-06 12:28:53 +04:00
|
|
|
}
|
2008-06-04 20:19:14 +04:00
|
|
|
break;
|
|
|
|
case ENOMEM:
|
|
|
|
rc = -1;
|
2013-08-02 17:19:41 +04:00
|
|
|
C_STRERROR(errno, errbuf, sizeof(errbuf));
|
2008-07-18 13:35:02 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"file: %s, command: open(O_CREAT), error: %s",
|
2012-03-07 18:42:07 +04:00
|
|
|
turi, errbuf);
|
2008-06-04 20:19:14 +04:00
|
|
|
goto out;
|
|
|
|
break;
|
|
|
|
default:
|
2013-08-02 17:19:41 +04:00
|
|
|
C_STRERROR(errno, errbuf, sizeof(errbuf));
|
2008-07-18 13:35:02 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"file: %s, command: open(O_CREAT), error: %s",
|
2012-03-07 18:42:07 +04:00
|
|
|
turi, errbuf);
|
2008-06-04 20:19:14 +04:00
|
|
|
rc = 1;
|
|
|
|
goto out;
|
|
|
|
break;
|
2008-05-19 18:29:01 +04:00
|
|
|
}
|
2008-06-04 20:19:14 +04:00
|
|
|
|
2008-05-16 19:30:57 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* copy file */
|
2012-12-04 18:03:49 +04:00
|
|
|
if( _use_fd_based_push(ctx) ) {
|
2013-03-02 18:02:27 +04:00
|
|
|
start_fd_based:
|
2013-03-11 22:02:18 +04:00
|
|
|
|
2013-03-02 18:02:27 +04:00
|
|
|
if (ctx->current == REMOTE_REPLICA) {
|
|
|
|
csync_win32_set_file_hidden(turi, true);
|
|
|
|
}
|
2012-12-10 21:58:46 +04:00
|
|
|
|
2013-03-11 22:02:18 +04:00
|
|
|
if (!_push_to_tmp_first(ctx)) {
|
|
|
|
csync_vio_set_property(ctx, "hbf_info", &hbf_info);
|
|
|
|
}
|
2012-12-10 21:58:46 +04:00
|
|
|
|
2012-12-04 18:03:49 +04:00
|
|
|
rc = csync_vio_sendfile( ctx, sfp, dfp );
|
2012-12-10 21:58:46 +04:00
|
|
|
|
2013-03-02 18:02:27 +04:00
|
|
|
if (ctx->current == REMOTE_REPLICA) {
|
2013-01-16 14:42:13 +04:00
|
|
|
csync_win32_set_file_hidden(turi, false);
|
2013-03-02 18:02:27 +04:00
|
|
|
}
|
2012-12-10 21:58:46 +04:00
|
|
|
|
2012-12-05 17:19:22 +04:00
|
|
|
if( rc != 0 ) {
|
2013-07-30 10:56:53 +04:00
|
|
|
if (rc == -1) {
|
|
|
|
/* Severe error */
|
|
|
|
switch(errno) {
|
|
|
|
case EINVAL:
|
|
|
|
ctx->error_code = CSYNC_ERR_PARAM;
|
|
|
|
break;
|
|
|
|
case ERRNO_USER_ABORT:
|
|
|
|
ctx->error_code = CSYNC_ERR_ABORTED;
|
|
|
|
break;
|
|
|
|
case ERRNO_GENERAL_ERROR:
|
|
|
|
default:
|
|
|
|
ctx->error_code = CSYNC_ERR_PROPAGATE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* fetch the error string from module. */
|
|
|
|
ctx->error_string = csync_vio_get_error_string(ctx);
|
|
|
|
}
|
|
|
|
|
2013-08-02 17:19:41 +04:00
|
|
|
C_STRERROR(errno, errbuf, sizeof(errbuf));
|
2012-12-05 17:19:22 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"file: %s, command: sendfile, error: %s from errno %d",
|
2013-07-30 10:56:53 +04:00
|
|
|
suri, c_streq(errbuf, "") ? csync_vio_get_error_string(ctx): errbuf, errno);
|
2013-03-02 18:02:27 +04:00
|
|
|
|
|
|
|
if (_push_to_tmp_first(ctx)) {
|
|
|
|
csync_vio_file_stat_t* sb = csync_vio_file_stat_new();
|
2013-07-15 12:48:14 +04:00
|
|
|
if (csync_vio_stat(ctx, turi, sb) == 0 && sb->size > 0
|
|
|
|
&& errno != EIO) {
|
|
|
|
/* EIO is mapped to error from owncloud like 500 for which we don't want to resume */
|
2013-03-02 18:02:27 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,
|
|
|
|
"keeping tmp file: %s", turi);
|
2013-04-04 14:58:29 +04:00
|
|
|
if (!progress_info) {
|
|
|
|
progress_info = c_malloc(sizeof(csync_progressinfo_t));
|
|
|
|
progress_info->error = 0;
|
|
|
|
progress_info->transferId = 0;
|
|
|
|
progress_info->md5 = st->md5 ? c_strdup(st->md5) : NULL;
|
|
|
|
progress_info->modtime = st->modtime;
|
|
|
|
progress_info->phash = st->phash;
|
2013-03-02 18:02:27 +04:00
|
|
|
} else {
|
2013-04-04 14:58:29 +04:00
|
|
|
SAFE_FREE(progress_info->tmpfile);
|
2013-03-02 18:02:27 +04:00
|
|
|
}
|
2013-04-04 14:58:29 +04:00
|
|
|
progress_info->chunk = 0;
|
|
|
|
progress_info->tmpfile = turi;
|
|
|
|
progress_info->error <<= 1;
|
2013-03-02 18:02:27 +04:00
|
|
|
turi = NULL;
|
|
|
|
}
|
|
|
|
csync_vio_file_stat_destroy(sb);
|
2013-03-11 22:02:18 +04:00
|
|
|
} else {
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,
|
|
|
|
"remember chunk: %d (transfer id %d )", hbf_info.start_id, hbf_info.transfer_id);
|
2013-04-04 14:58:29 +04:00
|
|
|
if (!progress_info) {
|
|
|
|
progress_info = c_malloc(sizeof(csync_progressinfo_t));
|
|
|
|
progress_info->error = 0;
|
|
|
|
progress_info->md5 = st->md5 ? c_strdup(st->md5) : NULL;
|
|
|
|
progress_info->modtime = st->modtime;
|
|
|
|
progress_info->phash = st->phash;
|
|
|
|
progress_info->tmpfile = NULL;
|
2013-03-11 22:02:18 +04:00
|
|
|
} else {
|
2013-04-04 14:58:29 +04:00
|
|
|
SAFE_FREE(progress_info->tmpfile);
|
2013-03-11 22:02:18 +04:00
|
|
|
}
|
2013-04-04 14:58:29 +04:00
|
|
|
progress_info->transferId = hbf_info.transfer_id;
|
|
|
|
progress_info->chunk = hbf_info.start_id;
|
2013-03-11 22:02:18 +04:00
|
|
|
csync_vio_set_property(ctx, "hbf_info", 0);
|
2013-03-02 18:02:27 +04:00
|
|
|
}
|
2013-05-16 19:37:30 +04:00
|
|
|
|
|
|
|
if( errno == ERRNO_USER_ABORT ) {
|
|
|
|
ctx->error_code = CSYNC_ERR_ABORTED;
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Csync file transmission was ABORTED by user!");
|
|
|
|
}
|
2012-12-05 17:19:22 +04:00
|
|
|
goto out;
|
|
|
|
}
|
2012-12-04 18:03:49 +04:00
|
|
|
} else {
|
|
|
|
for (;;) {
|
|
|
|
ctx->replica = srep;
|
|
|
|
bread = csync_vio_read(ctx, sfp, buf, MAX_XFER_BUF_SIZE);
|
|
|
|
|
|
|
|
if (bread < 0) {
|
|
|
|
/* read error */
|
2013-08-02 17:19:41 +04:00
|
|
|
C_STRERROR(errno, errbuf, sizeof(errbuf));
|
2012-12-04 18:03:49 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"file: %s, command: read, error: %s",
|
|
|
|
suri, errbuf);
|
|
|
|
rc = 1;
|
|
|
|
goto out;
|
|
|
|
} else if (bread == 0) {
|
|
|
|
/* done */
|
|
|
|
break;
|
|
|
|
}
|
2008-05-16 19:30:57 +04:00
|
|
|
|
2012-12-04 18:03:49 +04:00
|
|
|
ctx->replica = drep;
|
|
|
|
bwritten = csync_vio_write(ctx, dfp, buf, bread);
|
|
|
|
|
|
|
|
if (bwritten < 0 || bread != bwritten) {
|
2013-08-02 17:19:41 +04:00
|
|
|
C_STRERROR(errno, errbuf, sizeof(errbuf));
|
2012-12-04 18:03:49 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"file: %s, command: write, error: bread = %zu, bwritten = %zu - %s",
|
|
|
|
duri,
|
|
|
|
bread,
|
|
|
|
bwritten,
|
|
|
|
errbuf);
|
|
|
|
rc = 1;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
2008-05-16 19:30:57 +04:00
|
|
|
}
|
2008-06-18 18:30:00 +04:00
|
|
|
ctx->replica = srep;
|
2008-06-28 17:33:52 +04:00
|
|
|
if (csync_vio_close(ctx, sfp) < 0) {
|
2013-08-02 17:19:41 +04:00
|
|
|
C_STRERROR(errno, errbuf, sizeof(errbuf));
|
2008-06-28 17:33:52 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"file: %s, command: close, error: %s",
|
2008-07-18 13:35:02 +04:00
|
|
|
suri,
|
2012-03-07 18:42:07 +04:00
|
|
|
errbuf);
|
2008-06-28 17:33:52 +04:00
|
|
|
}
|
2008-06-18 18:30:00 +04:00
|
|
|
sfp = NULL;
|
|
|
|
|
|
|
|
ctx->replica = drep;
|
2008-06-28 17:33:52 +04:00
|
|
|
if (csync_vio_close(ctx, dfp) < 0) {
|
|
|
|
dfp = NULL;
|
|
|
|
switch (errno) {
|
2012-12-19 15:31:56 +04:00
|
|
|
/* stop if no space left or quota exceeded */
|
|
|
|
case ENOSPC:
|
|
|
|
case EDQUOT:
|
2013-08-02 17:19:41 +04:00
|
|
|
C_STRERROR(errno, errbuf, sizeof(errbuf));
|
2012-12-19 15:31:56 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"file: %s, command: close, error: %s",
|
|
|
|
turi,
|
|
|
|
errbuf);
|
|
|
|
rc = -1;
|
|
|
|
goto out;
|
|
|
|
break;
|
|
|
|
default:
|
2013-08-02 17:19:41 +04:00
|
|
|
C_STRERROR(errno, errbuf, sizeof(errbuf));
|
2012-12-19 15:31:56 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"file: %s, command: close, error: %s",
|
|
|
|
turi,
|
|
|
|
errbuf);
|
|
|
|
break;
|
2008-06-28 17:33:52 +04:00
|
|
|
}
|
|
|
|
}
|
2008-06-18 18:30:00 +04:00
|
|
|
dfp = NULL;
|
|
|
|
|
2012-07-04 17:03:15 +04:00
|
|
|
if( ctx->module.capabilities.do_post_copy_stat ) {
|
|
|
|
/*
|
|
|
|
* Check filesize
|
|
|
|
* In case the transport is secure and/or the stat is expensive, this check
|
|
|
|
* could be skipped through module capabilities definitions.
|
|
|
|
*/
|
|
|
|
|
|
|
|
ctx->replica = drep;
|
|
|
|
tstat = csync_vio_file_stat_new();
|
|
|
|
if (tstat == NULL) {
|
2013-08-02 17:19:41 +04:00
|
|
|
C_STRERROR(errno, errbuf, sizeof(errbuf));
|
2012-07-04 17:03:15 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"file: %s, command: stat, error: %s",
|
|
|
|
turi,
|
|
|
|
errbuf);
|
|
|
|
rc = -1;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (csync_vio_stat(ctx, turi, tstat) < 0) {
|
|
|
|
switch (errno) {
|
2008-05-19 18:29:01 +04:00
|
|
|
case ENOMEM:
|
|
|
|
rc = -1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rc = 1;
|
|
|
|
break;
|
2012-07-04 17:03:15 +04:00
|
|
|
}
|
2013-08-02 17:19:41 +04:00
|
|
|
C_STRERROR(errno, errbuf, sizeof(errbuf));
|
2012-07-04 17:03:15 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"file: %s, command: stat, error: %s",
|
|
|
|
turi,
|
|
|
|
errbuf);
|
|
|
|
goto out;
|
2008-05-19 18:29:01 +04:00
|
|
|
}
|
2008-05-16 19:30:57 +04:00
|
|
|
|
2012-07-04 17:03:15 +04:00
|
|
|
if (st->size != tstat->size) {
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
2013-07-31 16:50:44 +04:00
|
|
|
"file: %s, error: incorrect filesize (size: %" PRId64 " should be %" PRId64 ")",
|
2012-07-04 17:03:15 +04:00
|
|
|
turi, tstat->size, st->size);
|
|
|
|
rc = 1;
|
|
|
|
goto out;
|
|
|
|
}
|
2012-08-14 17:31:52 +04:00
|
|
|
|
2012-07-31 12:40:46 +04:00
|
|
|
if( st->md5 ) {
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "UUUU MD5 sum: %s", st->md5);
|
|
|
|
} else {
|
2012-08-23 18:40:36 +04:00
|
|
|
if( tstat->md5 ) {
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Target MD5 sum is %s", tstat->md5 );
|
2012-08-30 14:01:21 +04:00
|
|
|
if(st->md5) SAFE_FREE(st->md5);
|
2012-08-23 18:40:36 +04:00
|
|
|
st->md5 = c_strdup(tstat->md5 );
|
|
|
|
} else {
|
2012-07-31 12:40:46 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "MD5 sum is empty");
|
2012-08-23 18:40:36 +04:00
|
|
|
}
|
2012-07-31 12:40:46 +04:00
|
|
|
}
|
2008-05-16 19:30:57 +04:00
|
|
|
}
|
2012-06-22 17:32:04 +04:00
|
|
|
|
|
|
|
if (_push_to_tmp_first(ctx)) {
|
|
|
|
/* override original file */
|
|
|
|
ctx->replica = drep;
|
|
|
|
if (csync_vio_rename(ctx, turi, duri) < 0) {
|
|
|
|
switch (errno) {
|
2008-05-19 18:29:01 +04:00
|
|
|
case ENOMEM:
|
|
|
|
rc = -1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rc = 1;
|
|
|
|
break;
|
2012-06-22 17:32:04 +04:00
|
|
|
}
|
2013-08-02 17:19:41 +04:00
|
|
|
C_STRERROR(errno, errbuf, sizeof(errbuf));
|
2012-06-22 17:32:04 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"file: %s, command: rename, error: %s",
|
|
|
|
duri,
|
|
|
|
errbuf);
|
|
|
|
goto out;
|
2008-05-19 18:29:01 +04:00
|
|
|
}
|
2008-05-16 19:30:57 +04:00
|
|
|
}
|
2008-06-24 20:02:00 +04:00
|
|
|
/* set mode only if it is not the default mode */
|
|
|
|
if ((st->mode & 07777) != C_FILE_MODE) {
|
|
|
|
if (csync_vio_chmod(ctx, duri, st->mode) < 0) {
|
|
|
|
switch (errno) {
|
|
|
|
case ENOMEM:
|
|
|
|
rc = -1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rc = 1;
|
|
|
|
break;
|
|
|
|
}
|
2013-08-02 17:19:41 +04:00
|
|
|
C_STRERROR(errno, errbuf, sizeof(errbuf));
|
2008-07-18 13:35:02 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"file: %s, command: chmod, error: %s",
|
|
|
|
duri,
|
2012-03-07 18:42:07 +04:00
|
|
|
errbuf);
|
2008-06-24 20:02:00 +04:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-09 19:16:44 +04:00
|
|
|
/* set owner and group if possible */
|
2008-11-13 16:08:26 +03:00
|
|
|
if (ctx->pwd.euid == 0) {
|
2008-07-03 13:34:34 +04:00
|
|
|
csync_vio_chown(ctx, duri, st->uid, st->gid);
|
|
|
|
}
|
2008-06-09 19:16:44 +04:00
|
|
|
|
2008-05-16 19:30:57 +04:00
|
|
|
/* sync time */
|
|
|
|
times[0].tv_sec = times[1].tv_sec = st->modtime;
|
|
|
|
times[0].tv_usec = times[1].tv_usec = 0;
|
|
|
|
|
2008-05-19 13:21:44 +04:00
|
|
|
ctx->replica = drep;
|
2008-05-16 19:30:57 +04:00
|
|
|
csync_vio_utimes(ctx, duri, times);
|
|
|
|
|
2012-08-14 17:31:52 +04:00
|
|
|
|
|
|
|
/* For remote repos, after the utimes call, the ID has changed again */
|
2012-08-23 18:40:36 +04:00
|
|
|
/* do a stat on the target again to get a valid md5 */
|
2013-01-09 20:20:48 +04:00
|
|
|
tmd5 = _get_md5(ctx, auri);
|
2012-08-14 17:31:52 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "FINAL MD5: %s", tmd5 ? tmd5 : "<null>");
|
|
|
|
|
|
|
|
if(tmd5) {
|
|
|
|
SAFE_FREE(st->md5);
|
|
|
|
st->md5 = tmd5;
|
|
|
|
}
|
2012-08-23 18:40:36 +04:00
|
|
|
|
2008-09-02 13:43:29 +04:00
|
|
|
/* set instruction for the statedb merger */
|
2008-06-18 12:44:40 +04:00
|
|
|
st->instruction = CSYNC_INSTRUCTION_UPDATED;
|
2008-05-16 19:30:57 +04:00
|
|
|
|
2013-07-25 17:36:46 +04:00
|
|
|
/* Notify the progress */
|
2013-07-26 15:43:02 +04:00
|
|
|
ctx->overall_progress.byte_current += st->size;
|
2013-08-02 17:02:41 +04:00
|
|
|
_notify_progress(ctx, duri, st->size, notify_end_kind);
|
2013-05-06 19:14:17 +04:00
|
|
|
|
2011-04-12 19:06:18 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "PUSHED file: %s", duri);
|
2008-05-16 19:30:57 +04:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2008-09-02 13:43:29 +04:00
|
|
|
/* set instruction for the statedb merger */
|
2008-06-06 12:17:37 +04:00
|
|
|
if (rc != 0) {
|
2013-03-02 18:02:27 +04:00
|
|
|
if (_push_to_tmp_first(ctx)) {
|
|
|
|
if (turi != NULL) {
|
|
|
|
/* Remove the tmp file in error case. */
|
|
|
|
csync_vio_unlink(ctx, turi);
|
2012-12-19 15:41:16 +04:00
|
|
|
}
|
2012-10-19 20:34:12 +04:00
|
|
|
}
|
2013-06-07 18:43:48 +04:00
|
|
|
_csync_record_error(ctx, st, progress_info);
|
|
|
|
progress_info = NULL;
|
2008-06-06 12:17:37 +04:00
|
|
|
}
|
|
|
|
|
2013-04-04 14:58:29 +04:00
|
|
|
csync_statedb_free_progressinfo(progress_info);
|
2013-02-27 15:34:42 +04:00
|
|
|
|
2012-11-21 17:53:54 +04:00
|
|
|
SAFE_FREE(prev_tdir);
|
2008-05-16 19:30:57 +04:00
|
|
|
SAFE_FREE(suri);
|
|
|
|
SAFE_FREE(duri);
|
|
|
|
SAFE_FREE(turi);
|
|
|
|
SAFE_FREE(tdir);
|
2013-01-09 20:20:48 +04:00
|
|
|
SAFE_FREE(auri);
|
2008-05-16 19:30:57 +04:00
|
|
|
|
2009-01-23 16:07:34 +03:00
|
|
|
ctx->replica = rep_bak;
|
|
|
|
|
2008-05-16 19:30:57 +04:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2012-10-27 18:05:16 +04:00
|
|
|
static int _backup_path(CSYNC *ctx, char** duri, const char* uri, const char* path)
|
2011-04-06 18:43:04 +04:00
|
|
|
{
|
|
|
|
int rc=0;
|
|
|
|
C_PATHINFO *info=NULL;
|
2012-02-04 15:37:33 +04:00
|
|
|
|
2011-04-06 18:43:04 +04:00
|
|
|
struct tm *curtime;
|
|
|
|
time_t sec;
|
|
|
|
char timestring[16];
|
|
|
|
time(&sec);
|
|
|
|
curtime = localtime(&sec);
|
|
|
|
strftime(timestring, 16, "%Y%m%d-%H%M%S",curtime);
|
2012-02-04 15:37:33 +04:00
|
|
|
|
2011-04-06 18:43:04 +04:00
|
|
|
info=c_split_path(path);
|
2011-04-06 19:05:31 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,"directory: %s",info->directory);
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,"filename : %s",info->filename);
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,"extension: %s",info->extension);
|
2012-02-04 15:37:33 +04:00
|
|
|
|
2011-04-06 18:43:04 +04:00
|
|
|
if (asprintf(duri, "%s/%s%s_conflict-%s%s", uri,info->directory ,info->filename,timestring,info->extension) < 0) {
|
2012-02-04 15:37:33 +04:00
|
|
|
rc = -1;
|
2011-04-06 18:43:04 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
SAFE_FREE(info);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-23 00:04:09 +04:00
|
|
|
static int _csync_backup_file(CSYNC *ctx, csync_file_stat_t *st, char **duri) {
|
2011-04-06 18:43:04 +04:00
|
|
|
enum csync_replica_e drep = -1;
|
|
|
|
enum csync_replica_e rep_bak = -1;
|
|
|
|
|
|
|
|
char *suri = NULL;
|
|
|
|
|
|
|
|
char errbuf[256] = {0};
|
|
|
|
|
|
|
|
int rc = -1;
|
|
|
|
|
|
|
|
rep_bak = ctx->replica;
|
|
|
|
|
|
|
|
if(st->instruction==CSYNC_INSTRUCTION_CONFLICT)
|
|
|
|
{
|
2011-04-06 19:05:31 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,"CSYNC_INSTRUCTION_CONFLICT");
|
2011-04-06 18:43:04 +04:00
|
|
|
switch (ctx->current) {
|
|
|
|
case LOCAL_REPLICA:
|
|
|
|
drep = ctx->remote.type;
|
|
|
|
if (asprintf(&suri, "%s/%s", ctx->remote.uri, st->path) < 0) {
|
|
|
|
rc = -1;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2013-03-23 00:04:09 +04:00
|
|
|
if (_backup_path(ctx, duri, ctx->remote.uri,st->path) < 0) {
|
2011-04-06 18:43:04 +04:00
|
|
|
rc = -1;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
break;
|
2012-10-19 16:23:20 +04:00
|
|
|
case REMOTE_REPLICA:
|
2011-04-06 18:43:04 +04:00
|
|
|
drep = ctx->local.type;
|
|
|
|
if (asprintf(&suri, "%s/%s", ctx->local.uri, st->path) < 0) {
|
|
|
|
rc = -1;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2013-03-23 00:04:09 +04:00
|
|
|
if ( _backup_path(ctx, duri, ctx->local.uri, st->path) < 0) {
|
2011-04-06 18:43:04 +04:00
|
|
|
rc = -1;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
{
|
2011-04-06 19:05:31 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,"instruction not allowed: %i %s",st->instruction,csync_instruction_str(st->instruction));
|
2011-04-06 18:43:04 +04:00
|
|
|
rc = -1;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2011-04-06 19:05:31 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,"suri: %s",suri);
|
2013-03-23 00:04:09 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,"duri: %s",*duri);
|
2011-04-06 18:43:04 +04:00
|
|
|
|
|
|
|
|
|
|
|
/* rename the older file to conflict */
|
|
|
|
ctx->replica = drep;
|
2013-03-23 00:04:09 +04:00
|
|
|
if (csync_vio_rename(ctx, suri, *duri) < 0) {
|
2011-04-06 18:43:04 +04:00
|
|
|
switch (errno) {
|
|
|
|
case ENOMEM:
|
|
|
|
rc = -1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rc = 1;
|
|
|
|
break;
|
|
|
|
}
|
2013-08-02 17:19:41 +04:00
|
|
|
C_STRERROR(errno, errbuf, sizeof(errbuf));
|
2011-04-06 18:43:04 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"file: %s, command: rename, error: %s",
|
2013-03-23 00:04:09 +04:00
|
|
|
*duri,
|
2012-03-07 18:42:07 +04:00
|
|
|
errbuf);
|
2011-04-06 18:43:04 +04:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* set instruction for the statedb merger */
|
2011-04-12 12:09:41 +04:00
|
|
|
st->instruction = CSYNC_INSTRUCTION_NONE;
|
|
|
|
|
2013-03-23 00:04:09 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "BACKUP file: %s", *duri);
|
2011-04-06 18:43:04 +04:00
|
|
|
|
|
|
|
rc = 0;
|
|
|
|
|
|
|
|
out:
|
|
|
|
/* set instruction for the statedb merger */
|
|
|
|
if (rc != 0) {
|
2013-03-28 16:04:13 +04:00
|
|
|
_csync_file_stat_set_error(st, csync_get_error_string(ctx));
|
2011-04-06 18:43:04 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
SAFE_FREE(suri);
|
|
|
|
|
|
|
|
ctx->replica = rep_bak;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2008-05-20 16:01:04 +04:00
|
|
|
static int _csync_new_file(CSYNC *ctx, csync_file_stat_t *st) {
|
2008-05-16 19:30:57 +04:00
|
|
|
int rc = -1;
|
|
|
|
|
2008-05-20 16:01:04 +04:00
|
|
|
rc = _csync_push_file(ctx, st);
|
2008-05-16 19:30:57 +04:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2012-08-02 17:58:54 +04:00
|
|
|
static int _csync_rename_file(CSYNC *ctx, csync_file_stat_t *st) {
|
|
|
|
int rc = 0;
|
|
|
|
char errbuf[256] = {0};
|
2012-08-09 17:59:08 +04:00
|
|
|
struct timeval times[2];
|
2012-08-02 17:58:54 +04:00
|
|
|
char *suri = NULL;
|
|
|
|
char *duri = NULL;
|
2012-09-24 16:55:18 +04:00
|
|
|
c_rbnode_t *node = NULL;
|
2013-01-08 03:15:23 +04:00
|
|
|
char *tdir = NULL;
|
2013-02-09 00:51:03 +04:00
|
|
|
csync_file_stat_t *other = NULL;
|
2013-02-27 15:34:42 +04:00
|
|
|
csync_progressinfo_t *pi = NULL;
|
2013-03-06 23:26:01 +04:00
|
|
|
|
|
|
|
/* Find the destination entry in the local tree */
|
|
|
|
uint64_t h = c_jhash64((uint8_t *) st->destpath, strlen(st->destpath), 0);
|
|
|
|
node = c_rbtree_find(ctx->local.tree, &h);
|
|
|
|
if(node)
|
|
|
|
other = (csync_file_stat_t *) node->data;
|
|
|
|
|
2013-06-18 20:15:43 +04:00
|
|
|
#ifdef BLACKLIST_ON_ERROR
|
2013-03-06 23:26:01 +04:00
|
|
|
if (other) {
|
|
|
|
pi = csync_statedb_get_progressinfo(ctx, other->phash, other->modtime, other->md5);
|
|
|
|
if (pi && pi->error > 3) {
|
2013-06-18 20:15:43 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"'%s' was blacklisted after %d errors: %s",
|
|
|
|
st->path, pi->error, pi->error_string);
|
2013-03-28 16:21:55 +04:00
|
|
|
if (!st->error_string && pi->error_string)
|
|
|
|
st->error_string = c_strdup(pi->error_string);
|
2013-04-24 16:52:57 +04:00
|
|
|
if (!other->error_string && pi->error_string)
|
|
|
|
other->error_string = c_strdup(pi->error_string);
|
2013-03-06 23:26:01 +04:00
|
|
|
rc = 1;
|
|
|
|
goto out;
|
|
|
|
}
|
2013-02-27 15:34:42 +04:00
|
|
|
}
|
2013-06-18 20:15:43 +04:00
|
|
|
#endif
|
2013-02-27 15:34:42 +04:00
|
|
|
|
2012-08-02 17:58:54 +04:00
|
|
|
switch (ctx->current) {
|
2012-10-27 21:27:14 +04:00
|
|
|
case REMOTE_REPLICA:
|
2012-08-02 17:58:54 +04:00
|
|
|
if( !(st->path && st->destpath) ) {
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Rename failed: src or dest path empty");
|
|
|
|
rc = -1;
|
2013-07-04 14:18:08 +04:00
|
|
|
goto out;
|
2012-08-02 17:58:54 +04:00
|
|
|
}
|
2013-01-04 23:45:10 +04:00
|
|
|
if (_csync_build_remote_uri(ctx, &suri, st->path) < 0) {
|
2012-08-02 17:58:54 +04:00
|
|
|
rc = -1;
|
|
|
|
}
|
2013-01-04 23:45:10 +04:00
|
|
|
if (_csync_build_remote_uri(ctx, &duri, st->destpath) < 0) {
|
2012-08-02 17:58:54 +04:00
|
|
|
rc = -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LOCAL_REPLICA:
|
|
|
|
/* No renaming supported by updater */
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "RENAME is only supported on local filesystem.");
|
|
|
|
rc = -1;
|
2012-10-18 15:26:17 +04:00
|
|
|
goto out;
|
2012-08-02 17:58:54 +04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-01-08 03:15:23 +04:00
|
|
|
if (! c_streq(suri, duri) && rc > -1) {
|
2013-07-04 14:18:08 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Renaming %s => %s", suri, duri);
|
2013-01-08 03:15:23 +04:00
|
|
|
while ((rc = csync_vio_rename(ctx, suri, duri)) != 0) {
|
2013-01-05 14:32:24 +04:00
|
|
|
switch (errno) {
|
2013-01-08 03:15:23 +04:00
|
|
|
case ENOENT:
|
|
|
|
/* get the directory name */
|
|
|
|
if(tdir) {
|
|
|
|
/* we're looping */
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN,
|
|
|
|
"dir: %s, loop in mkdir detected!", tdir);
|
|
|
|
rc = 1;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
tdir = c_dirname(duri);
|
|
|
|
if (tdir == NULL) {
|
|
|
|
rc = -1;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (csync_vio_mkdirs(ctx, tdir, C_DIR_MODE) < 0) {
|
2013-08-02 17:19:41 +04:00
|
|
|
C_STRERROR(errno, errbuf, sizeof(errbuf));
|
2013-01-08 03:15:23 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN,
|
|
|
|
"dir: %s, command: mkdirs, error: %s",
|
|
|
|
tdir, errbuf);
|
|
|
|
}
|
|
|
|
break;
|
2013-01-05 14:32:24 +04:00
|
|
|
default:
|
2013-08-02 17:19:41 +04:00
|
|
|
C_STRERROR(errno, errbuf, sizeof(errbuf));
|
2013-01-05 14:32:24 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"dir: %s, command: rename, error: %s",
|
|
|
|
suri,
|
|
|
|
errbuf);
|
2013-01-08 03:15:23 +04:00
|
|
|
goto out;
|
2013-01-05 14:32:24 +04:00
|
|
|
}
|
2012-08-02 17:58:54 +04:00
|
|
|
}
|
|
|
|
|
2013-01-05 14:32:24 +04:00
|
|
|
/* set owner and group if possible */
|
|
|
|
if (ctx->pwd.euid == 0) {
|
|
|
|
csync_vio_chown(ctx, duri, st->uid, st->gid);
|
|
|
|
}
|
2012-08-09 17:59:08 +04:00
|
|
|
|
2013-01-05 14:32:24 +04:00
|
|
|
/* sync time */
|
|
|
|
times[0].tv_sec = times[1].tv_sec = st->modtime;
|
|
|
|
times[0].tv_usec = times[1].tv_usec = 0;
|
2012-08-09 17:59:08 +04:00
|
|
|
|
2013-01-05 14:32:24 +04:00
|
|
|
csync_vio_utimes(ctx, duri, times);
|
|
|
|
|
|
|
|
}
|
2012-08-09 17:59:08 +04:00
|
|
|
|
2012-08-02 17:58:54 +04:00
|
|
|
if( rc > -1 ) {
|
2013-02-09 00:51:03 +04:00
|
|
|
/* set the mtime which is needed in statedb_get_uniqid */
|
|
|
|
if( other ) {
|
2013-07-08 15:23:12 +04:00
|
|
|
if (st->type != CSYNC_FTW_TYPE_DIR) {
|
|
|
|
other->md5 = _get_md5(ctx, st->destpath);
|
|
|
|
} else {
|
|
|
|
/* For directories, re-use the old md5 */
|
|
|
|
other->md5 = c_strdup(st->md5);
|
|
|
|
}
|
2012-09-24 16:55:18 +04:00
|
|
|
}
|
|
|
|
/* set instruction for the statedb merger */
|
|
|
|
st->instruction = CSYNC_INSTRUCTION_DELETED;
|
2012-08-02 17:58:54 +04:00
|
|
|
}
|
2012-09-24 16:55:18 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "RENAME file: %s => %s with ID %s", st->path, st->destpath, st->md5);
|
2012-08-02 17:58:54 +04:00
|
|
|
|
|
|
|
out:
|
|
|
|
SAFE_FREE(suri);
|
|
|
|
SAFE_FREE(duri);
|
2013-01-08 03:15:23 +04:00
|
|
|
SAFE_FREE(tdir);
|
2012-08-02 17:58:54 +04:00
|
|
|
|
|
|
|
/* set instruction for the statedb merger */
|
|
|
|
if (rc != 0) {
|
2013-03-28 16:04:13 +04:00
|
|
|
_csync_file_stat_set_error(st, csync_get_error_string(ctx));
|
2013-02-12 18:11:15 +04:00
|
|
|
if (other) {
|
2013-02-27 15:34:42 +04:00
|
|
|
|
2013-02-12 18:11:15 +04:00
|
|
|
/* We set the instruction to UPDATED so next try we try to rename again */
|
|
|
|
st->instruction = CSYNC_INSTRUCTION_UPDATED;
|
2013-03-06 23:26:01 +04:00
|
|
|
|
|
|
|
_csync_record_error(ctx, other, pi);
|
|
|
|
pi = NULL;
|
2013-02-12 18:11:15 +04:00
|
|
|
}
|
2012-08-02 17:58:54 +04:00
|
|
|
}
|
|
|
|
|
2013-02-27 15:34:42 +04:00
|
|
|
csync_statedb_free_progressinfo(pi);
|
2012-08-02 17:58:54 +04:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2008-05-20 16:01:04 +04:00
|
|
|
static int _csync_sync_file(CSYNC *ctx, csync_file_stat_t *st) {
|
2008-05-16 19:30:57 +04:00
|
|
|
int rc = -1;
|
|
|
|
|
2008-05-20 16:01:04 +04:00
|
|
|
rc = _csync_push_file(ctx, st);
|
2008-05-16 19:30:57 +04:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2011-04-06 18:43:04 +04:00
|
|
|
static int _csync_conflict_file(CSYNC *ctx, csync_file_stat_t *st) {
|
|
|
|
int rc = -1;
|
2013-03-23 00:04:09 +04:00
|
|
|
char *conflict_file_name;
|
|
|
|
char *uri = NULL;
|
|
|
|
|
|
|
|
rc = _csync_backup_file(ctx, st, &conflict_file_name);
|
2011-04-06 18:43:04 +04:00
|
|
|
|
|
|
|
if(rc>=0)
|
|
|
|
{
|
|
|
|
rc = _csync_push_file(ctx, st);
|
|
|
|
}
|
|
|
|
|
2013-03-23 00:04:09 +04:00
|
|
|
if( rc >= 0 ) {
|
|
|
|
/* if its the local repository, check if both files are equal. */
|
|
|
|
if( ctx->current == REMOTE_REPLICA ) {
|
|
|
|
if (asprintf(&uri, "%s/%s", ctx->local.uri, st->path) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( c_compare_file(uri, conflict_file_name) == 1 ) {
|
|
|
|
/* the files are byte wise equal. The conflict can be erased. */
|
|
|
|
if (csync_vio_local_unlink(conflict_file_name) < 0) {
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "REMOVE of csync conflict file %s failed.", conflict_file_name );
|
|
|
|
} else {
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "REMOVED csync conflict file %s as files are equal.",
|
|
|
|
conflict_file_name );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-06 18:43:04 +04:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2008-05-20 16:01:04 +04:00
|
|
|
static int _csync_remove_file(CSYNC *ctx, csync_file_stat_t *st) {
|
2008-07-18 13:35:02 +04:00
|
|
|
char errbuf[256] = {0};
|
2008-05-16 19:30:57 +04:00
|
|
|
char *uri = NULL;
|
2008-05-19 18:29:01 +04:00
|
|
|
int rc = -1;
|
2008-05-16 19:30:57 +04:00
|
|
|
|
2013-02-27 15:34:42 +04:00
|
|
|
csync_progressinfo_t *pi = NULL;
|
2013-06-18 20:15:43 +04:00
|
|
|
#ifdef BLACKLIST_ON_ERROR
|
2013-02-27 15:34:42 +04:00
|
|
|
pi = csync_statedb_get_progressinfo(ctx, st->phash, st->modtime, st->md5);
|
|
|
|
if (pi && pi->error > 3) {
|
2013-06-18 20:15:43 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"'%s' was blacklisted after %d errors: %s",
|
|
|
|
st->path, pi->error, pi->error_string);
|
2013-02-27 15:34:42 +04:00
|
|
|
rc = 1;
|
2013-03-28 16:21:55 +04:00
|
|
|
if (!st->error_string && pi->error_string)
|
|
|
|
st->error_string = c_strdup(pi->error_string);
|
2013-02-27 15:34:42 +04:00
|
|
|
goto out;
|
|
|
|
}
|
2013-06-18 20:15:43 +04:00
|
|
|
#endif
|
2013-02-27 15:34:42 +04:00
|
|
|
|
|
|
|
|
2008-05-16 19:30:57 +04:00
|
|
|
switch (ctx->current) {
|
|
|
|
case LOCAL_REPLICA:
|
|
|
|
if (asprintf(&uri, "%s/%s", ctx->local.uri, st->path) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
2012-10-19 16:23:20 +04:00
|
|
|
case REMOTE_REPLICA:
|
2013-01-04 23:45:10 +04:00
|
|
|
if (_csync_build_remote_uri(ctx, &uri, st->path) < 0) {
|
2008-05-16 19:30:57 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-08-02 17:01:46 +04:00
|
|
|
_notify_progress(ctx, uri, st->size, CSYNC_NOTIFY_START_DELETE);
|
2008-05-19 18:29:01 +04:00
|
|
|
if (csync_vio_unlink(ctx, uri) < 0) {
|
|
|
|
switch (errno) {
|
|
|
|
case ENOMEM:
|
|
|
|
rc = -1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rc = 1;
|
|
|
|
break;
|
|
|
|
}
|
2013-08-02 17:19:41 +04:00
|
|
|
C_STRERROR(errno, errbuf, sizeof(errbuf));
|
2008-07-18 13:35:02 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"file: %s, command: unlink, error: %s",
|
|
|
|
uri,
|
2012-03-07 18:42:07 +04:00
|
|
|
errbuf);
|
2008-05-19 18:29:01 +04:00
|
|
|
goto out;
|
|
|
|
}
|
2008-05-16 19:30:57 +04:00
|
|
|
|
2008-09-02 13:43:29 +04:00
|
|
|
/* set instruction for the statedb merger */
|
2008-06-18 11:56:08 +04:00
|
|
|
st->instruction = CSYNC_INSTRUCTION_DELETED;
|
2013-08-02 17:01:46 +04:00
|
|
|
_notify_progress(ctx, uri, st->size, CSYNC_NOTIFY_END_DELETE);
|
2008-05-16 19:30:57 +04:00
|
|
|
|
2011-04-12 19:06:18 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "REMOVED file: %s", uri);
|
2008-05-16 19:30:57 +04:00
|
|
|
|
2008-05-19 18:29:01 +04:00
|
|
|
rc = 0;
|
|
|
|
out:
|
|
|
|
SAFE_FREE(uri);
|
2008-06-28 19:18:10 +04:00
|
|
|
|
2008-09-02 13:42:34 +04:00
|
|
|
/* set instruction for the statedb merger */
|
|
|
|
if (rc != 0) {
|
|
|
|
/* Write file to statedb, to try to sync again on the next run. */
|
|
|
|
st->instruction = CSYNC_INSTRUCTION_NONE;
|
2013-02-27 15:34:42 +04:00
|
|
|
_csync_record_error(ctx, st, pi);
|
|
|
|
pi = NULL;
|
2008-09-02 13:42:34 +04:00
|
|
|
}
|
2008-06-28 19:18:10 +04:00
|
|
|
|
2013-02-27 15:34:42 +04:00
|
|
|
csync_statedb_free_progressinfo(pi);
|
2008-05-19 18:29:01 +04:00
|
|
|
return rc;
|
2008-05-16 19:30:57 +04:00
|
|
|
}
|
|
|
|
|
2008-05-20 16:01:04 +04:00
|
|
|
static int _csync_new_dir(CSYNC *ctx, csync_file_stat_t *st) {
|
2008-09-11 16:16:04 +04:00
|
|
|
enum csync_replica_e dest = -1;
|
2008-05-16 19:30:57 +04:00
|
|
|
enum csync_replica_e replica_bak;
|
2008-07-18 13:35:02 +04:00
|
|
|
char errbuf[256] = {0};
|
2008-05-19 18:29:01 +04:00
|
|
|
char *uri = NULL;
|
2008-05-16 19:30:57 +04:00
|
|
|
struct timeval times[2];
|
2008-05-19 18:29:01 +04:00
|
|
|
int rc = -1;
|
2008-05-16 19:30:57 +04:00
|
|
|
|
2013-02-27 15:34:42 +04:00
|
|
|
csync_progressinfo_t *pi = NULL;
|
2013-06-18 20:15:43 +04:00
|
|
|
#ifdef BLACKLIST_ON_ERROR
|
2013-02-27 15:34:42 +04:00
|
|
|
pi = csync_statedb_get_progressinfo(ctx, st->phash, st->modtime, st->md5);
|
|
|
|
if (pi && pi->error > 3) {
|
2013-06-18 20:15:43 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"'%s' was blacklisted after %d errors: %s",
|
|
|
|
st->path, pi->error, pi->error_string);
|
2013-03-28 16:21:55 +04:00
|
|
|
if (!st->error_string && pi->error_string)
|
|
|
|
st->error_string = c_strdup(pi->error_string);
|
2013-02-27 15:34:42 +04:00
|
|
|
rc = 1;
|
|
|
|
goto out;
|
|
|
|
}
|
2013-06-18 20:15:43 +04:00
|
|
|
#endif
|
2013-02-27 15:34:42 +04:00
|
|
|
|
2008-05-16 19:30:57 +04:00
|
|
|
replica_bak = ctx->replica;
|
|
|
|
|
|
|
|
switch (ctx->current) {
|
|
|
|
case LOCAL_REPLICA:
|
|
|
|
dest = ctx->remote.type;
|
2013-01-04 23:45:10 +04:00
|
|
|
if (_csync_build_remote_uri(ctx, &uri, st->path) < 0) {
|
2008-05-16 19:30:57 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
2012-10-19 16:23:20 +04:00
|
|
|
case REMOTE_REPLICA:
|
2008-05-16 19:30:57 +04:00
|
|
|
dest = ctx->local.type;
|
2008-05-19 18:29:01 +04:00
|
|
|
if (asprintf(&uri, "%s/%s", ctx->local.uri, st->path) < 0) {
|
2008-05-16 19:30:57 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx->replica = dest;
|
2008-06-24 20:02:00 +04:00
|
|
|
if (csync_vio_mkdirs(ctx, uri, C_DIR_MODE) < 0) {
|
2008-05-19 18:29:01 +04:00
|
|
|
switch (errno) {
|
|
|
|
case ENOMEM:
|
|
|
|
rc = -1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rc = 1;
|
|
|
|
break;
|
|
|
|
}
|
2013-08-02 17:19:41 +04:00
|
|
|
C_STRERROR(errno, errbuf, sizeof(errbuf));
|
2008-07-18 13:35:02 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"dir: %s, command: mkdirs, error: %s",
|
|
|
|
uri,
|
2012-03-07 18:42:07 +04:00
|
|
|
errbuf);
|
2008-05-19 18:29:01 +04:00
|
|
|
goto out;
|
|
|
|
}
|
2008-05-16 19:30:57 +04:00
|
|
|
|
2008-06-24 20:02:00 +04:00
|
|
|
/* chmod is if it is not the default mode */
|
|
|
|
if ((st->mode & 07777) != C_DIR_MODE) {
|
|
|
|
if (csync_vio_chmod(ctx, uri, st->mode) < 0) {
|
|
|
|
switch (errno) {
|
|
|
|
case ENOMEM:
|
|
|
|
rc = -1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rc = 1;
|
|
|
|
break;
|
|
|
|
}
|
2013-08-02 17:19:41 +04:00
|
|
|
C_STRERROR(errno, errbuf, sizeof(errbuf));
|
2008-07-18 13:35:02 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"dir: %s, command: chmod, error: %s",
|
|
|
|
uri,
|
2012-03-07 18:42:07 +04:00
|
|
|
errbuf);
|
2008-06-24 20:02:00 +04:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
2008-06-05 16:43:28 +04:00
|
|
|
|
2008-06-09 19:16:44 +04:00
|
|
|
/* set owner and group if possible */
|
2008-11-13 16:08:26 +03:00
|
|
|
if (ctx->pwd.euid == 0) {
|
2008-07-03 13:34:34 +04:00
|
|
|
csync_vio_chown(ctx, uri, st->uid, st->gid);
|
|
|
|
}
|
2008-06-09 19:16:44 +04:00
|
|
|
|
2008-05-16 19:30:57 +04:00
|
|
|
times[0].tv_sec = times[1].tv_sec = st->modtime;
|
|
|
|
times[0].tv_usec = times[1].tv_usec = 0;
|
|
|
|
|
2008-05-19 18:29:01 +04:00
|
|
|
csync_vio_utimes(ctx, uri, times);
|
2008-05-16 19:30:57 +04:00
|
|
|
|
2008-09-02 13:43:29 +04:00
|
|
|
/* set instruction for the statedb merger */
|
2008-06-18 12:44:40 +04:00
|
|
|
st->instruction = CSYNC_INSTRUCTION_UPDATED;
|
2008-05-16 19:30:57 +04:00
|
|
|
|
2011-04-12 19:06:18 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "CREATED dir: %s", uri);
|
2008-05-16 19:30:57 +04:00
|
|
|
ctx->replica = replica_bak;
|
|
|
|
|
2008-05-19 18:29:01 +04:00
|
|
|
rc = 0;
|
|
|
|
out:
|
|
|
|
SAFE_FREE(uri);
|
2008-06-28 19:18:10 +04:00
|
|
|
|
2008-09-02 13:42:34 +04:00
|
|
|
/* set instruction for the statedb merger */
|
|
|
|
if (rc != 0) {
|
2013-02-27 15:34:42 +04:00
|
|
|
_csync_record_error(ctx, st, pi);
|
|
|
|
pi = NULL;
|
2008-09-02 13:42:34 +04:00
|
|
|
}
|
2008-06-28 19:18:10 +04:00
|
|
|
|
2013-02-27 15:34:42 +04:00
|
|
|
csync_statedb_free_progressinfo(pi);
|
2008-05-19 18:29:01 +04:00
|
|
|
return rc;
|
2008-05-16 19:30:57 +04:00
|
|
|
}
|
|
|
|
|
2008-05-20 16:01:04 +04:00
|
|
|
static int _csync_sync_dir(CSYNC *ctx, csync_file_stat_t *st) {
|
2008-09-11 16:16:04 +04:00
|
|
|
enum csync_replica_e dest = -1;
|
2008-05-16 19:30:57 +04:00
|
|
|
enum csync_replica_e replica_bak;
|
2008-07-18 13:35:02 +04:00
|
|
|
char errbuf[256] = {0};
|
2008-05-19 18:29:01 +04:00
|
|
|
char *uri = NULL;
|
2008-05-16 19:30:57 +04:00
|
|
|
struct timeval times[2];
|
2008-05-19 18:29:01 +04:00
|
|
|
int rc = -1;
|
2008-05-16 19:30:57 +04:00
|
|
|
|
2013-02-27 15:34:42 +04:00
|
|
|
csync_progressinfo_t *pi = NULL;
|
2013-06-18 20:15:43 +04:00
|
|
|
#ifdef BLACKLIST_ON_ERROR
|
2013-02-27 15:34:42 +04:00
|
|
|
pi = csync_statedb_get_progressinfo(ctx, st->phash, st->modtime, st->md5);
|
|
|
|
if (pi && pi->error > 3) {
|
2013-06-18 20:15:43 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"'%s' was blacklisted after %d errors: %s",
|
|
|
|
st->path, pi->error, pi->error_string);
|
2013-03-28 16:21:55 +04:00
|
|
|
if (!st->error_string && pi->error_string)
|
|
|
|
st->error_string = c_strdup(pi->error_string);
|
2013-02-27 15:34:42 +04:00
|
|
|
rc = 1;
|
|
|
|
goto out;
|
|
|
|
}
|
2013-06-18 20:15:43 +04:00
|
|
|
#endif
|
2013-02-27 15:34:42 +04:00
|
|
|
|
2008-05-16 19:30:57 +04:00
|
|
|
replica_bak = ctx->replica;
|
|
|
|
|
|
|
|
switch (ctx->current) {
|
|
|
|
case LOCAL_REPLICA:
|
|
|
|
dest = ctx->remote.type;
|
2013-01-04 23:45:10 +04:00
|
|
|
if (_csync_build_remote_uri(ctx, &uri, st->path) < 0) {
|
2008-05-16 19:30:57 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
2012-10-19 16:23:20 +04:00
|
|
|
case REMOTE_REPLICA:
|
2008-05-16 19:30:57 +04:00
|
|
|
dest = ctx->local.type;
|
2008-05-19 18:29:01 +04:00
|
|
|
if (asprintf(&uri, "%s/%s", ctx->local.uri, st->path) < 0) {
|
2008-05-16 19:30:57 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx->replica = dest;
|
|
|
|
|
2008-06-24 20:02:00 +04:00
|
|
|
/* chmod is if it is not the default mode */
|
|
|
|
if ((st->mode & 07777) != C_DIR_MODE) {
|
|
|
|
if (csync_vio_chmod(ctx, uri, st->mode) < 0) {
|
|
|
|
switch (errno) {
|
|
|
|
case ENOMEM:
|
|
|
|
rc = -1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rc = 1;
|
|
|
|
break;
|
|
|
|
}
|
2013-08-02 17:19:41 +04:00
|
|
|
C_STRERROR(errno, errbuf, sizeof(errbuf));
|
2008-07-18 13:35:02 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"dir: %s, command: chmod, error: %s",
|
|
|
|
uri,
|
2012-03-07 18:42:07 +04:00
|
|
|
errbuf);
|
2008-06-24 20:02:00 +04:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-09 19:16:44 +04:00
|
|
|
/* set owner and group if possible */
|
2008-11-13 16:08:26 +03:00
|
|
|
if (ctx->pwd.euid == 0) {
|
2008-07-03 13:34:34 +04:00
|
|
|
csync_vio_chown(ctx, uri, st->uid, st->gid);
|
|
|
|
}
|
2008-06-09 19:16:44 +04:00
|
|
|
|
2008-05-16 19:30:57 +04:00
|
|
|
times[0].tv_sec = times[1].tv_sec = st->modtime;
|
|
|
|
times[0].tv_usec = times[1].tv_usec = 0;
|
|
|
|
|
2008-05-19 18:29:01 +04:00
|
|
|
csync_vio_utimes(ctx, uri, times);
|
2008-09-02 13:43:29 +04:00
|
|
|
/* set instruction for the statedb merger */
|
2008-06-28 19:18:10 +04:00
|
|
|
st->instruction = CSYNC_INSTRUCTION_UPDATED;
|
2008-05-16 19:30:57 +04:00
|
|
|
|
2011-04-12 19:06:18 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "SYNCED dir: %s", uri);
|
2012-08-17 17:48:56 +04:00
|
|
|
|
2008-05-16 19:30:57 +04:00
|
|
|
ctx->replica = replica_bak;
|
|
|
|
|
2008-05-19 18:29:01 +04:00
|
|
|
rc = 0;
|
|
|
|
out:
|
|
|
|
SAFE_FREE(uri);
|
2008-06-28 19:18:10 +04:00
|
|
|
|
2008-09-02 13:43:29 +04:00
|
|
|
/* set instruction for the statedb merger */
|
2008-06-28 19:18:10 +04:00
|
|
|
if (rc != 0) {
|
2013-02-27 15:34:42 +04:00
|
|
|
_csync_record_error(ctx, st, pi);
|
|
|
|
pi = NULL;
|
2008-06-28 19:18:10 +04:00
|
|
|
}
|
|
|
|
|
2013-02-27 15:34:42 +04:00
|
|
|
csync_statedb_free_progressinfo(pi);
|
2008-05-19 18:29:01 +04:00
|
|
|
return rc;
|
2008-05-16 19:30:57 +04:00
|
|
|
}
|
|
|
|
|
2013-02-13 21:12:20 +04:00
|
|
|
/* If a remove operation failed, we need to update the st so the information
|
|
|
|
that will be stored in the database will make it so that we try to remove
|
|
|
|
again on the next sync. */
|
|
|
|
static void _csync_remove_error(CSYNC *ctx, csync_file_stat_t *st, char *uri) {
|
|
|
|
/* Write it back to statedb, that we try to delete it next time. */
|
|
|
|
st->instruction = CSYNC_INSTRUCTION_NONE;
|
|
|
|
|
|
|
|
if (ctx->replica == LOCAL_REPLICA) {
|
|
|
|
/* Update the mtime */
|
|
|
|
csync_vio_file_stat_t* vst = csync_vio_file_stat_new();
|
|
|
|
if (csync_vio_stat(ctx, uri, vst) == 0) {
|
|
|
|
st->inode = vst->inode;
|
|
|
|
st->modtime = vst->mtime;
|
|
|
|
}
|
|
|
|
csync_vio_file_stat_destroy(vst);
|
|
|
|
|
|
|
|
/* don't write the md5 to the database */
|
|
|
|
SAFE_FREE(st->md5);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-20 16:01:04 +04:00
|
|
|
static int _csync_remove_dir(CSYNC *ctx, csync_file_stat_t *st) {
|
2008-05-20 15:56:43 +04:00
|
|
|
c_list_t *list = NULL;
|
2008-07-18 13:35:02 +04:00
|
|
|
char errbuf[256] = {0};
|
2008-05-19 18:29:01 +04:00
|
|
|
char *uri = NULL;
|
|
|
|
int rc = -1;
|
2013-04-26 12:31:30 +04:00
|
|
|
csync_file_stat_t **pst;
|
|
|
|
|
2008-05-16 19:30:57 +04:00
|
|
|
|
|
|
|
switch (ctx->current) {
|
|
|
|
case LOCAL_REPLICA:
|
2008-05-19 18:29:01 +04:00
|
|
|
if (asprintf(&uri, "%s/%s", ctx->local.uri, st->path) < 0) {
|
2008-05-16 19:30:57 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
2012-10-19 16:23:20 +04:00
|
|
|
case REMOTE_REPLICA:
|
2013-01-04 23:45:10 +04:00
|
|
|
if (_csync_build_remote_uri(ctx, &uri, st->path) < 0) {
|
2008-05-16 19:30:57 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-05-19 18:29:01 +04:00
|
|
|
if (csync_vio_rmdir(ctx, uri) < 0) {
|
|
|
|
switch (errno) {
|
|
|
|
case ENOMEM:
|
2013-08-02 17:19:41 +04:00
|
|
|
C_STRERROR(errno, errbuf, sizeof(errbuf));
|
2008-07-18 13:35:02 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL,
|
|
|
|
"dir: %s, command: rmdir, error: %s",
|
|
|
|
uri,
|
2012-03-07 18:42:07 +04:00
|
|
|
errbuf);
|
2008-05-19 18:29:01 +04:00
|
|
|
rc = -1;
|
|
|
|
break;
|
|
|
|
case ENOTEMPTY:
|
2013-04-26 12:31:30 +04:00
|
|
|
pst = c_malloc(sizeof(csync_file_stat_t*));
|
|
|
|
*pst = st;
|
|
|
|
|
2008-05-20 15:56:43 +04:00
|
|
|
switch (ctx->current) {
|
|
|
|
case LOCAL_REPLICA:
|
2013-04-26 12:31:30 +04:00
|
|
|
list = c_list_prepend(ctx->local.list, (void *) pst);
|
2008-05-20 15:56:43 +04:00
|
|
|
if (list == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
ctx->local.list = list;
|
|
|
|
break;
|
2012-10-19 16:23:20 +04:00
|
|
|
case REMOTE_REPLICA:
|
2013-04-26 12:31:30 +04:00
|
|
|
list = c_list_prepend(ctx->remote.list, (void *) pst);
|
2008-05-20 15:56:43 +04:00
|
|
|
if (list == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
ctx->remote.list = list;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
rc = 0;
|
2008-05-19 18:29:01 +04:00
|
|
|
break;
|
|
|
|
default:
|
2013-08-02 17:19:41 +04:00
|
|
|
C_STRERROR(errno, errbuf, sizeof(errbuf));
|
2008-07-18 13:35:02 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
|
|
|
"dir: %s, command: rmdir, error: %s",
|
|
|
|
uri,
|
2012-03-07 18:42:07 +04:00
|
|
|
errbuf);
|
2008-05-19 18:29:01 +04:00
|
|
|
rc = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
goto out;
|
|
|
|
}
|
2008-05-16 19:30:57 +04:00
|
|
|
|
2008-09-02 13:43:29 +04:00
|
|
|
/* set instruction for the statedb merger */
|
2008-06-18 11:56:08 +04:00
|
|
|
st->instruction = CSYNC_INSTRUCTION_DELETED;
|
2008-05-16 19:30:57 +04:00
|
|
|
|
2011-04-12 19:06:18 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "REMOVED dir: %s", uri);
|
2008-05-16 19:30:57 +04:00
|
|
|
|
2008-05-19 18:29:01 +04:00
|
|
|
rc = 0;
|
|
|
|
out:
|
2008-06-28 19:18:10 +04:00
|
|
|
|
2008-09-02 13:43:29 +04:00
|
|
|
/* set instruction for the statedb merger */
|
2008-06-28 19:18:10 +04:00
|
|
|
if (rc != 0) {
|
2013-02-13 21:12:20 +04:00
|
|
|
_csync_remove_error(ctx, st, uri);
|
2008-06-28 19:18:10 +04:00
|
|
|
}
|
|
|
|
|
2013-02-13 21:12:20 +04:00
|
|
|
SAFE_FREE(uri);
|
2008-05-19 18:29:01 +04:00
|
|
|
return rc;
|
2008-05-16 19:30:57 +04:00
|
|
|
}
|
|
|
|
|
2008-05-20 15:56:43 +04:00
|
|
|
static int _csync_propagation_cleanup(CSYNC *ctx) {
|
|
|
|
c_list_t *list = NULL;
|
|
|
|
c_list_t *walk = NULL;
|
2013-07-26 14:37:54 +04:00
|
|
|
c_list_t *walk2 = NULL;
|
|
|
|
c_list_t *ignored_cleanup = NULL;
|
2008-05-20 15:56:43 +04:00
|
|
|
char *uri = NULL;
|
|
|
|
char *dir = NULL;
|
|
|
|
|
|
|
|
switch (ctx->current) {
|
|
|
|
case LOCAL_REPLICA:
|
|
|
|
list = ctx->local.list;
|
2013-07-26 14:37:54 +04:00
|
|
|
ignored_cleanup = ctx->local.ignored_cleanup;
|
2008-05-20 15:56:43 +04:00
|
|
|
uri = ctx->local.uri;
|
|
|
|
break;
|
2012-10-19 16:23:20 +04:00
|
|
|
case REMOTE_REPLICA:
|
2008-05-20 15:56:43 +04:00
|
|
|
list = ctx->remote.list;
|
2013-07-26 14:37:54 +04:00
|
|
|
ignored_cleanup = ctx->remote.ignored_cleanup;
|
2008-05-20 15:56:43 +04:00
|
|
|
uri = ctx->remote.uri;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (list == NULL) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
list = c_list_sort(list, _csync_cleanup_cmp);
|
|
|
|
if (list == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (walk = c_list_last(list); walk != NULL; walk = c_list_prev(walk)) {
|
|
|
|
csync_file_stat_t *st = NULL;
|
2013-05-22 14:15:53 +04:00
|
|
|
csync_file_stat_t **pst = NULL;
|
2008-05-20 15:56:43 +04:00
|
|
|
|
2013-05-22 14:15:53 +04:00
|
|
|
pst = (csync_file_stat_t **) walk->data;
|
|
|
|
st = *(pst);
|
2008-05-20 15:56:43 +04:00
|
|
|
|
2013-07-26 14:37:54 +04:00
|
|
|
|
|
|
|
/* Cleanup ignored files */
|
|
|
|
for (walk2 = c_list_last(ignored_cleanup); walk2 != NULL; walk2 = c_list_prev(walk2)) {
|
|
|
|
const char *fn = (const char*) walk2->data;
|
|
|
|
/* check if the file name does not starts with the path to remove. */
|
|
|
|
if (strlen(fn) < st->pathlen || fn[st->pathlen] != '/'
|
|
|
|
|| strncmp(fn, st->path, st->pathlen) != 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (asprintf(&dir, "%s/%s", uri, fn) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Removing ignored file %s ", dir);
|
|
|
|
|
|
|
|
if (csync_vio_unlink(ctx, dir) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
SAFE_FREE(dir);
|
|
|
|
}
|
|
|
|
|
2008-05-20 15:56:43 +04:00
|
|
|
if (asprintf(&dir, "%s/%s", uri, st->path) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-07-26 14:37:54 +04:00
|
|
|
|
2008-06-28 19:18:10 +04:00
|
|
|
if (csync_vio_rmdir(ctx, dir) < 0) {
|
2013-02-13 21:12:20 +04:00
|
|
|
_csync_remove_error(ctx, st, uri);
|
2008-06-28 19:18:10 +04:00
|
|
|
} else {
|
|
|
|
st->instruction = CSYNC_INSTRUCTION_DELETED;
|
|
|
|
}
|
2008-05-20 15:56:43 +04:00
|
|
|
|
2011-04-12 19:06:18 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "CLEANUP dir: %s", dir);
|
2008-05-20 15:56:43 +04:00
|
|
|
|
|
|
|
SAFE_FREE(dir);
|
2013-05-22 14:15:53 +04:00
|
|
|
SAFE_FREE(pst);
|
2008-05-20 15:56:43 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-05-06 19:14:17 +04:00
|
|
|
static int _csync_propagation_file_count_visitor(void *obj, void *data) {
|
|
|
|
csync_file_stat_t *st = NULL;
|
|
|
|
CSYNC *ctx = NULL;
|
|
|
|
|
|
|
|
st = (csync_file_stat_t *) obj;
|
|
|
|
ctx = (CSYNC *) data;
|
|
|
|
|
|
|
|
if (st == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (ctx == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(st->type) {
|
|
|
|
case CSYNC_FTW_TYPE_SLINK:
|
|
|
|
break;
|
|
|
|
case CSYNC_FTW_TYPE_FILE:
|
|
|
|
switch (st->instruction) {
|
|
|
|
case CSYNC_INSTRUCTION_NEW:
|
|
|
|
case CSYNC_INSTRUCTION_SYNC:
|
|
|
|
case CSYNC_INSTRUCTION_CONFLICT:
|
2013-07-25 17:36:46 +04:00
|
|
|
ctx->overall_progress.file_count++;
|
|
|
|
ctx->overall_progress.byte_sum += st->size;
|
2013-05-06 19:14:17 +04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CSYNC_FTW_TYPE_DIR:
|
|
|
|
/*
|
|
|
|
* No counting of directories.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-05-20 16:01:04 +04:00
|
|
|
static int _csync_propagation_file_visitor(void *obj, void *data) {
|
2008-05-16 19:30:57 +04:00
|
|
|
csync_file_stat_t *st = NULL;
|
|
|
|
CSYNC *ctx = NULL;
|
2013-02-27 15:34:42 +04:00
|
|
|
int rc = 0;
|
2008-05-16 19:30:57 +04:00
|
|
|
|
|
|
|
st = (csync_file_stat_t *) obj;
|
|
|
|
ctx = (CSYNC *) data;
|
|
|
|
|
2013-05-08 17:28:26 +04:00
|
|
|
if (ctx->abort) {
|
2013-06-19 20:41:30 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Aborted!");
|
2013-05-08 17:28:26 +04:00
|
|
|
ctx->error_code = CSYNC_ERR_ABORTED;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2008-05-16 19:30:57 +04:00
|
|
|
switch(st->type) {
|
2008-05-26 19:09:42 +04:00
|
|
|
case CSYNC_FTW_TYPE_SLINK:
|
|
|
|
break;
|
2008-05-16 19:30:57 +04:00
|
|
|
case CSYNC_FTW_TYPE_FILE:
|
|
|
|
switch (st->instruction) {
|
|
|
|
case CSYNC_INSTRUCTION_NEW:
|
2013-02-27 15:34:42 +04:00
|
|
|
if ((rc = _csync_new_file(ctx, st)) < 0) {
|
2012-06-22 17:32:04 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,"FAIL NEW: %s",st->path);
|
2008-05-19 13:21:44 +04:00
|
|
|
goto err;
|
|
|
|
}
|
2008-05-16 19:30:57 +04:00
|
|
|
break;
|
2012-08-02 17:58:54 +04:00
|
|
|
case CSYNC_INSTRUCTION_SYNC:
|
2013-02-27 15:34:42 +04:00
|
|
|
if ((rc = _csync_sync_file(ctx, st)) < 0) {
|
2012-06-22 17:32:04 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,"FAIL SYNC: %s",st->path);
|
2008-05-19 13:30:41 +04:00
|
|
|
goto err;
|
|
|
|
}
|
2008-05-16 19:30:57 +04:00
|
|
|
break;
|
|
|
|
case CSYNC_INSTRUCTION_REMOVE:
|
2013-02-27 15:34:42 +04:00
|
|
|
if ((rc = _csync_remove_file(ctx, st)) < 0) {
|
2012-06-22 17:32:04 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,"FAIL REMOVE: %s",st->path);
|
2008-05-19 13:30:41 +04:00
|
|
|
goto err;
|
|
|
|
}
|
2008-05-16 19:30:57 +04:00
|
|
|
break;
|
2011-04-06 18:43:04 +04:00
|
|
|
case CSYNC_INSTRUCTION_CONFLICT:
|
2011-04-06 19:05:31 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,"case CSYNC_INSTRUCTION_CONFLICT: %s",st->path);
|
2013-02-27 15:34:42 +04:00
|
|
|
if ((rc = _csync_conflict_file(ctx, st)) < 0) {
|
2011-04-06 18:43:04 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
break;
|
2008-05-16 19:30:57 +04:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2008-05-19 13:39:11 +04:00
|
|
|
case CSYNC_FTW_TYPE_DIR:
|
|
|
|
/*
|
|
|
|
* We have to walk over the files first. If you create or rename a file
|
|
|
|
* in a directory on unix. The modification time of the directory gets
|
|
|
|
* changed.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-02-27 15:34:42 +04:00
|
|
|
return rc;
|
2008-05-19 13:39:11 +04:00
|
|
|
err:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2008-05-20 16:01:04 +04:00
|
|
|
static int _csync_propagation_dir_visitor(void *obj, void *data) {
|
2008-05-19 13:39:11 +04:00
|
|
|
csync_file_stat_t *st = NULL;
|
|
|
|
CSYNC *ctx = NULL;
|
|
|
|
|
|
|
|
st = (csync_file_stat_t *) obj;
|
|
|
|
ctx = (CSYNC *) data;
|
|
|
|
|
2013-05-08 17:28:26 +04:00
|
|
|
if (ctx->abort) {
|
2013-06-19 20:41:30 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Aborted!");
|
2013-05-08 17:28:26 +04:00
|
|
|
ctx->error_code = CSYNC_ERR_ABORTED;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2008-05-19 13:39:11 +04:00
|
|
|
switch(st->type) {
|
2008-05-26 19:09:42 +04:00
|
|
|
case CSYNC_FTW_TYPE_SLINK:
|
|
|
|
/* FIXME: implement symlink support */
|
|
|
|
break;
|
2008-05-19 13:39:11 +04:00
|
|
|
case CSYNC_FTW_TYPE_FILE:
|
|
|
|
break;
|
2008-05-16 19:30:57 +04:00
|
|
|
case CSYNC_FTW_TYPE_DIR:
|
|
|
|
switch (st->instruction) {
|
|
|
|
case CSYNC_INSTRUCTION_NEW:
|
2008-05-20 16:01:04 +04:00
|
|
|
if (_csync_new_dir(ctx, st) < 0) {
|
2008-05-16 19:30:57 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CSYNC_INSTRUCTION_SYNC:
|
2008-05-20 16:01:04 +04:00
|
|
|
if (_csync_sync_dir(ctx, st) < 0) {
|
2008-05-16 19:30:57 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
break;
|
2011-04-06 18:43:04 +04:00
|
|
|
case CSYNC_INSTRUCTION_CONFLICT:
|
2011-04-12 19:06:18 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,"directory attributes different");
|
2011-04-06 18:43:04 +04:00
|
|
|
if (_csync_sync_dir(ctx, st) < 0) {
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
break;
|
2008-05-16 19:30:57 +04:00
|
|
|
case CSYNC_INSTRUCTION_REMOVE:
|
2008-05-20 16:01:04 +04:00
|
|
|
if (_csync_remove_dir(ctx, st) < 0) {
|
2008-05-19 13:39:11 +04:00
|
|
|
goto err;
|
|
|
|
}
|
2012-08-17 17:48:56 +04:00
|
|
|
break;
|
2012-08-09 17:59:08 +04:00
|
|
|
case CSYNC_INSTRUCTION_RENAME:
|
|
|
|
/* there can't be a rename for dirs. See updater. */
|
2008-05-16 19:30:57 +04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
err:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-01-06 22:46:30 +04:00
|
|
|
int csync_propagate_rename_file(CSYNC *ctx, csync_file_stat_t *st) {
|
|
|
|
return _csync_rename_file(ctx, st);
|
2013-01-04 23:45:10 +04:00
|
|
|
}
|
|
|
|
|
2013-07-22 14:55:24 +04:00
|
|
|
/* Count the files to transmit for both up- and download, ie. in both replicas. */
|
2013-08-02 23:03:01 +04:00
|
|
|
int csync_init_progress(CSYNC *ctx) {
|
2013-07-22 14:55:24 +04:00
|
|
|
|
|
|
|
if (ctx == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-07-25 17:36:46 +04:00
|
|
|
if (ctx->callbacks.progress_cb == NULL) {
|
2013-07-22 14:55:24 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx->current = REMOTE_REPLICA;
|
|
|
|
ctx->replica = ctx->remote.type;
|
|
|
|
|
|
|
|
if (c_rbtree_walk(ctx->remote.tree, (void *) ctx, _csync_propagation_file_count_visitor) < 0) {
|
|
|
|
ctx->error_code = CSYNC_ERR_TREE;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
ctx->current = LOCAL_REPLICA;
|
|
|
|
ctx->replica = ctx->local.type;
|
|
|
|
|
|
|
|
if (c_rbtree_walk(ctx->local.tree, (void *) ctx, _csync_propagation_file_count_visitor) < 0) {
|
|
|
|
ctx->error_code = CSYNC_ERR_TREE;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-07-25 17:36:46 +04:00
|
|
|
/* Notify the progress */
|
|
|
|
csync_set_module_property(ctx, "overall_progress_data", &(ctx->overall_progress));
|
|
|
|
|
2013-08-06 14:10:00 +04:00
|
|
|
_notify_progress(ctx, NULL, 0, CSYNC_NOTIFY_START_SYNC_SEQUENCE);
|
2013-07-22 14:55:24 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-25 17:36:46 +04:00
|
|
|
void csync_finalize_progress(CSYNC *ctx) {
|
2013-08-02 17:02:41 +04:00
|
|
|
_notify_progress(ctx, NULL, 0, CSYNC_NOTIFY_FINISHED_SYNC_SEQUENCE);
|
2013-07-25 17:36:46 +04:00
|
|
|
|
|
|
|
csync_set_module_property(ctx, "overall_progress_data", NULL);
|
|
|
|
}
|
|
|
|
|
2008-12-14 01:29:16 +03:00
|
|
|
int csync_propagate_files(CSYNC *ctx) {
|
2008-05-16 19:30:57 +04:00
|
|
|
c_rbtree_t *tree = NULL;
|
|
|
|
|
|
|
|
switch (ctx->current) {
|
|
|
|
case LOCAL_REPLICA:
|
|
|
|
tree = ctx->local.tree;
|
|
|
|
break;
|
2012-10-19 16:23:20 +04:00
|
|
|
case REMOTE_REPLICA:
|
2008-05-16 19:30:57 +04:00
|
|
|
tree = ctx->remote.tree;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-05-20 16:01:04 +04:00
|
|
|
if (c_rbtree_walk(tree, (void *) ctx, _csync_propagation_file_visitor) < 0) {
|
2008-05-19 13:39:11 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2008-05-20 16:01:04 +04:00
|
|
|
if (c_rbtree_walk(tree, (void *) ctx, _csync_propagation_dir_visitor) < 0) {
|
2008-05-16 19:30:57 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2008-05-20 15:56:43 +04:00
|
|
|
if (_csync_propagation_cleanup(ctx) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
2008-05-16 19:30:57 +04:00
|
|
|
return 0;
|
|
|
|
}
|
2008-05-19 18:29:01 +04:00
|
|
|
|
2013-01-04 23:45:10 +04:00
|
|
|
|
2009-05-13 12:12:07 +04:00
|
|
|
/* vim: set ts=8 sw=2 et cindent: */
|