mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-27 17:37:36 +03:00
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:
parent
9380869d01
commit
8034da83cc
4 changed files with 97 additions and 23 deletions
28
src/csync.c
28
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.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;
|
||||||
|
|
17
src/csync.h
17
src/csync.h
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue