Ability to push to remote without using a tempfile to copy to.

Modules such as ownCloud make sure anyway that the upload to a
remote resource happens atomar. This patch allows to switch off
the default behaviour of first copying to a temp file in the
same directory. Use csync_set_remote_push_atomar function to
switch off.
This commit is contained in:
Klaas Freitag 2012-06-22 15:32:04 +02:00
parent 9380869d01
commit 8034da83cc
4 changed files with 97 additions and 23 deletions

View file

@ -121,6 +121,7 @@ int csync_create(CSYNC **csync, const char *local, const char *remote) {
ctx->options.unix_extensions = 0; ctx->options.unix_extensions = 0;
ctx->options.with_conflict_copys=false; ctx->options.with_conflict_copys=false;
ctx->options.local_only_mode = false; ctx->options.local_only_mode = false;
ctx->options.remote_push_atomar = false;
ctx->pwd.uid = getuid(); ctx->pwd.uid = getuid();
ctx->pwd.euid = geteuid(); ctx->pwd.euid = geteuid();
@ -937,6 +938,33 @@ bool csync_get_local_only(CSYNC *ctx) {
return ctx->options.local_only_mode; 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) { CSYNC_ERROR_CODE csync_get_error(CSYNC *ctx) {
if (ctx == NULL) { if (ctx == NULL) {
return CSYNC_ERR_PARAM; return CSYNC_ERR_PARAM;

View file

@ -375,6 +375,23 @@ int csync_set_local_only( CSYNC *ctx, bool local_only );
*/ */
bool csync_get_local_only( CSYNC *ctx ); 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 */ /* Used for special modes or debugging */
int csync_get_status(CSYNC *ctx); int csync_get_status(CSYNC *ctx);

View file

@ -118,6 +118,7 @@ struct csync_s {
char *config_dir; char *config_dir;
bool with_conflict_copys; bool with_conflict_copys;
bool local_only_mode; bool local_only_mode;
bool remote_push_atomar;
} options; } options;
struct { struct {

View file

@ -46,6 +46,12 @@ static int _csync_cleanup_cmp(const void *a, const void *b) {
return strcmp(st_a->path, st_b->path); 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) { static int _csync_push_file(CSYNC *ctx, csync_file_stat_t *st) {
enum csync_replica_e srep = -1; enum csync_replica_e srep = -1;
enum csync_replica_e drep = -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; goto out;
} }
/* create the temporary file name */ if (_push_to_tmp_first(ctx)) {
if (asprintf(&turi, "%s.XXXXXX", duri) < 0) { /* create the temporary file name */
rc = -1; if (asprintf(&turi, "%s.XXXXXX", duri) < 0) {
goto out; 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 */ /* Create the destination file */
ctx->replica = drep; ctx->replica = drep;
while ((dfp = csync_vio_open(ctx, turi, O_CREAT|O_EXCL|O_WRONLY|O_NOCTTY, while ((dfp = csync_vio_open(ctx, turi, O_CREAT|O_EXCL|O_WRONLY|O_NOCTTY,
C_FILE_MODE)) == NULL) { C_FILE_MODE)) == NULL) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,
"file: %s, command: open(O_CREAT), error: %d",
duri, errno);
switch (errno) { switch (errno) {
case EEXIST: case EEXIST:
if (count++ > 10) { if (count++ > 10) {
@ -150,9 +171,11 @@ static int _csync_push_file(CSYNC *ctx, csync_file_stat_t *st) {
rc = 1; rc = 1;
goto out; goto out;
} }
if (c_tmpname(turi) < 0) { if(_push_to_tmp_first(ctx)) {
rc = -1; if (c_tmpname(turi) < 0) {
goto out; rc = -1;
goto out;
}
} }
break; break;
case ENOENT: case ENOENT:
@ -299,25 +322,27 @@ static int _csync_push_file(CSYNC *ctx, csync_file_stat_t *st) {
goto out; goto out;
} }
#endif #endif
/* override original file */
ctx->replica = drep; if (_push_to_tmp_first(ctx)) {
if (csync_vio_rename(ctx, turi, duri) < 0) { /* override original file */
switch (errno) { ctx->replica = drep;
if (csync_vio_rename(ctx, turi, duri) < 0) {
switch (errno) {
case ENOMEM: case ENOMEM:
rc = -1; rc = -1;
break; break;
default: default:
rc = 1; rc = 1;
break; 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 */ /* set mode only if it is not the default mode */
if ((st->mode & 07777) != C_FILE_MODE) { if ((st->mode & 07777) != C_FILE_MODE) {
if (csync_vio_chmod(ctx, duri, st->mode) < 0) { 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) { switch (st->instruction) {
case CSYNC_INSTRUCTION_NEW: case CSYNC_INSTRUCTION_NEW:
if (_csync_new_file(ctx, st) < 0) { if (_csync_new_file(ctx, st) < 0) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,"FAIL NEW: %s",st->path);
goto err; goto err;
} }
break; break;
case CSYNC_INSTRUCTION_SYNC: case CSYNC_INSTRUCTION_SYNC:
if (_csync_sync_file(ctx, st) < 0) { if (_csync_sync_file(ctx, st) < 0) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,"FAIL SYNC: %s",st->path);
goto err; goto err;
} }
break; break;
case CSYNC_INSTRUCTION_REMOVE: case CSYNC_INSTRUCTION_REMOVE:
if (_csync_remove_file(ctx, st) < 0) { if (_csync_remove_file(ctx, st) < 0) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,"FAIL REMOVE: %s",st->path);
goto err; goto err;
} }
break; break;