diff --git a/src/csync.c b/src/csync.c index b68a984c04..b6e4589bc0 100644 --- a/src/csync.c +++ b/src/csync.c @@ -121,6 +121,7 @@ int csync_create(CSYNC **csync, const char *local, const char *remote) { ctx->options.unix_extensions = 0; ctx->options.with_conflict_copys=false; ctx->options.local_only_mode = false; + ctx->options.remote_push_atomar = false; ctx->pwd.uid = getuid(); ctx->pwd.euid = geteuid(); @@ -937,6 +938,33 @@ bool csync_get_local_only(CSYNC *ctx) { return ctx->options.local_only_mode; } +int csync_set_remote_push_atomar(CSYNC *ctx, bool is_atomar) { + if(ctx == NULL) { + return -1; + } + + ctx->error_code = CSYNC_ERR_NONE; + + if (ctx->status & CSYNC_STATUS_PROPAGATE) { + fprintf(stderr, "This function must be called before propagation."); + ctx->error_code = CSYNC_ERR_UNSPEC; + return -1; + } + + ctx->options.remote_push_atomar = is_atomar; + + return 0; +} + +bool csync_get_remote_push_atomar(CSYNC *ctx) { + if (ctx == NULL) { + return -1; + } + ctx->error_code = CSYNC_ERR_NONE; + + return ctx->options.remote_push_atomar; +} + CSYNC_ERROR_CODE csync_get_error(CSYNC *ctx) { if (ctx == NULL) { return CSYNC_ERR_PARAM; diff --git a/src/csync.h b/src/csync.h index 81d07517cb..087e5b5729 100644 --- a/src/csync.h +++ b/src/csync.h @@ -375,6 +375,23 @@ int csync_set_local_only( CSYNC *ctx, bool local_only ); */ bool csync_get_local_only( CSYNC *ctx ); +/** + * @brief Flag to tell csync that the push to remote is atomar and no temp file is needed. + * + * @param local_only Bool flag to indicate atomar remote push + * + * @return 0 on success, less than 0 if an error occured. + */ +int csync_set_remote_push_atomar(CSYNC *ctx, bool is_atomar); + +/** + * @brief Retrieve the flag if the remote push is atomar and needs no temp file in between. + * + * @return 1: remote push is atomar, 0: use temp file to push + */ +bool csync_get_remote_push_atomar( CSYNC *ctx ); + + /* Used for special modes or debugging */ int csync_get_status(CSYNC *ctx); diff --git a/src/csync_private.h b/src/csync_private.h index 1cb1a3790f..2b4d9359a8 100644 --- a/src/csync_private.h +++ b/src/csync_private.h @@ -118,6 +118,7 @@ struct csync_s { char *config_dir; bool with_conflict_copys; bool local_only_mode; + bool remote_push_atomar; } options; struct { diff --git a/src/csync_propagate.c b/src/csync_propagate.c index 01d6415ae2..2e37f6b9de 100644 --- a/src/csync_propagate.c +++ b/src/csync_propagate.c @@ -46,6 +46,12 @@ static int _csync_cleanup_cmp(const void *a, const void *b) { return strcmp(st_a->path, st_b->path); } +static bool _push_to_tmp_first(CSYNC *ctx) +{ + if( ctx->current == REMOTE_REPLCIA && !ctx->options.remote_push_atomar ) return true; + return false; +} + static int _csync_push_file(CSYNC *ctx, csync_file_stat_t *st) { enum csync_replica_e srep = -1; enum csync_replica_e drep = -1; @@ -125,22 +131,37 @@ static int _csync_push_file(CSYNC *ctx, csync_file_stat_t *st) { goto out; } - /* create the temporary file name */ - if (asprintf(&turi, "%s.XXXXXX", duri) < 0) { - rc = -1; - goto out; - } + if (_push_to_tmp_first(ctx)) { + /* create the temporary file name */ + if (asprintf(&turi, "%s.XXXXXX", duri) < 0) { + rc = -1; + goto out; + } + + /* We just want a random file name here, open checks if the file exists. */ + if (c_tmpname(turi) < 0) { + 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, + "Remote repository atomar push enabled for %s.", turi ); - /* We just want a random file name here, open checks if the file exists. */ - if (c_tmpname(turi) < 0) { - rc = -1; - goto out; } /* Create the destination file */ ctx->replica = drep; while ((dfp = csync_vio_open(ctx, turi, O_CREAT|O_EXCL|O_WRONLY|O_NOCTTY, C_FILE_MODE)) == NULL) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, + "file: %s, command: open(O_CREAT), error: %d", + duri, errno); + switch (errno) { case EEXIST: if (count++ > 10) { @@ -150,9 +171,11 @@ static int _csync_push_file(CSYNC *ctx, csync_file_stat_t *st) { rc = 1; goto out; } - if (c_tmpname(turi) < 0) { - rc = -1; - goto out; + if(_push_to_tmp_first(ctx)) { + if (c_tmpname(turi) < 0) { + rc = -1; + goto out; + } } break; case ENOENT: @@ -299,25 +322,27 @@ static int _csync_push_file(CSYNC *ctx, csync_file_stat_t *st) { goto out; } #endif - /* override original file */ - ctx->replica = drep; - if (csync_vio_rename(ctx, turi, duri) < 0) { - switch (errno) { + + if (_push_to_tmp_first(ctx)) { + /* override original file */ + ctx->replica = drep; + if (csync_vio_rename(ctx, turi, duri) < 0) { + switch (errno) { case ENOMEM: rc = -1; break; default: rc = 1; break; + } + strerror_r(errno, errbuf, sizeof(errbuf)); + CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, + "file: %s, command: rename, error: %s", + duri, + errbuf); + goto out; } - strerror_r(errno, errbuf, sizeof(errbuf)); - CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, - "file: %s, command: rename, error: %s", - duri, - errbuf); - goto out; } - /* 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) { @@ -907,16 +932,19 @@ static int _csync_propagation_file_visitor(void *obj, void *data) { switch (st->instruction) { case CSYNC_INSTRUCTION_NEW: if (_csync_new_file(ctx, st) < 0) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,"FAIL NEW: %s",st->path); goto err; } break; case CSYNC_INSTRUCTION_SYNC: if (_csync_sync_file(ctx, st) < 0) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,"FAIL SYNC: %s",st->path); goto err; } break; case CSYNC_INSTRUCTION_REMOVE: if (_csync_remove_file(ctx, st) < 0) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,"FAIL REMOVE: %s",st->path); goto err; } break;