Comparar commits

..

3 Commits

Autor SHA1 Mensagem Data
Olivier Goffart cfdfd6a860 wizard: don't call initializePage
It is called automatically by QWizard and do not need to be called explicitly

But setVisibla(false) don't really have an effect there since show() is going
to be called on the page
2014-07-30 12:36:30 +02:00
Olivier Goffart 5254c9785c shibboleth: Fix connection when the URL do not have a path
When the url do not have a path (for example: "http://example.com" as
opposed to "http://example.com/"),  its path is not a prefix of the
root path of the cookie (usually '/')

By adding the dav path, we make sure the URL has a path.

This made a bug when the owncloud url was just a domain name and did not
have a path
2014-07-28 13:50:24 +02:00
Klaas Freitag 0f37484b8a Bumped the release number to 1.6.2, Changelog additions. 2014-07-28 11:44:10 +02:00
121 arquivos alterados com 4244 adições e 4151 exclusões
+1 -4
Ver Arquivo
@@ -108,10 +108,7 @@ if(NOT TOKEN_AUTH_ONLY)
endif()
endif()
if(APPLE)
find_package(Sparkle)
endif(APPLE)
Find_package(Sparkle)
if(UNIX)
find_package(INotify REQUIRED)
else()
+2 -1
Ver Arquivo
@@ -1,6 +1,7 @@
ChangeLog
=========
version 1.6.2 (release 2014-07-x )
version 1.6.2 (release 2014-07-28 )
* Limit the HTTP buffer size when downloading to limit memory consumption.
* Another small mem leak fixed in HTTP Credentials.
* Fix local file name clash detection for MacOSX.
* Limit maximum wait time to ten seconds in network limiting.
+3 -3
Ver Arquivo
@@ -1,10 +1,10 @@
set( MIRALL_VERSION_MAJOR 1 )
set( MIRALL_VERSION_MINOR 7 )
set( MIRALL_VERSION_PATCH 0 )
set( MIRALL_VERSION_MINOR 6 )
set( MIRALL_VERSION_PATCH 2 )
set( MIRALL_SOVERSION 0 )
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )
set( MIRALL_VERSION_SUFFIX "prealpha") #e.g. beta1, beta2, rc1
set( MIRALL_VERSION_SUFFIX "") #e.g. beta1, beta2, rc1
endif( NOT DEFINED MIRALL_VERSION_SUFFIX )
if( NOT DEFINED MIRALL_VERSION_BUILD )
+1 -1
Ver Arquivo
@@ -13,7 +13,7 @@ if (${CMAKE_C_COMPILER_ID} MATCHES "(GNU|Clang)")
if (NOT CSYNC_STATIC_COMPILE_DIR)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -pedantic -pedantic-errors")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wshadow -Wmissing-prototypes")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wshadow -Wmissing-prototypes -Wdeclaration-after-statement")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused -Wfloat-equal -Wpointer-arith -Wwrite-strings -Wformat-security")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-format-attribute")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-format-attribute -D_GNU_SOURCE")
+3 -9
Ver Arquivo
@@ -19,11 +19,10 @@ if( Qt5Core_FOUND )
find_package(Qt5PrintSupport REQUIRED)
find_package(Qt5Quick REQUIRED)
find_package(Qt5Widgets REQUIRED)
if(APPLE)
find_package(Qt5MacExtras REQUIRED)
endif(APPLE)
endif()
if(APPLE)
find_package(Qt5MacExtras REQUIRED)
endif(APPLE)
else( Qt5Core_FOUND )
if(WIN32 OR APPLE)
message(FATAL_ERROR "Qt 5 not found, but application depends on Qt5 on Windows and Mac OS X")
@@ -66,15 +65,10 @@ endif()
qt5_add_resources(${ARGN})
endmacro()
if(NOT TOKEN_AUTH_ONLY)
find_package(Qt5LinguistTools REQUIRED)
macro(qt_add_translation)
qt5_add_translation(${ARGN})
endmacro()
else()
macro(qt_add_translation)
endmacro()
endif()
macro(qt_add_dbus_interface)
qt5_add_dbus_interface(${ARGN})
-2
Ver Arquivo
@@ -6,11 +6,9 @@ if(CMAKE_COMPILER_IS_GNUCXX)
else(GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wno-long-long")
endif(GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif(CMAKE_COMPILER_IS_GNUCXX)
if(CMAKE_CXX_COMPILER MATCHES "clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wno-long-long")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif(CMAKE_CXX_COMPILER MATCHES "clang")
# TODO: handle msvc compilers warnings?
+7 -7
Ver Arquivo
@@ -27,6 +27,10 @@ include(MacroCopyFile)
if (NOT WIN32)
find_package(Iconv)
endif (NOT WIN32)
find_package(CMocka)
if (CMOCKA_FOUND AND UNIT_TESTING)
include(AddCMockaTest)
endif (CMOCKA_FOUND AND UNIT_TESTING)
include(ConfigureChecks.cmake)
@@ -43,13 +47,9 @@ endif (MEM_NULL_TESTS)
add_subdirectory(src)
if (UNIT_TESTING)
find_package(CMocka)
if (CMOCKA_FOUND)
include(AddCMockaTest)
add_subdirectory(tests)
endif (CMOCKA_FOUND)
endif (UNIT_TESTING)
if (CMOCKA_FOUND AND UNIT_TESTING)
add_subdirectory(tests)
endif (CMOCKA_FOUND AND UNIT_TESTING)
configure_file(config_csync.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config_csync.h)
configure_file(config_test.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config_test.h)
+2 -2
Ver Arquivo
@@ -96,10 +96,10 @@ include_directories(
)
add_library(${CSYNC_LIBRARY} SHARED ${csync_SRCS})
#add_library(${CSYNC_LIBRARY}_static STATIC ${csync_SRCS})
add_library(${CSYNC_LIBRARY}_static STATIC ${csync_SRCS})
target_link_libraries(${CSYNC_LIBRARY} ${CSYNC_LINK_LIBRARIES})
#target_link_libraries(${CSYNC_LIBRARY}_static ${CSYNC_LINK_LIBRARIES})
target_link_libraries(${CSYNC_LIBRARY}_static ${CSYNC_LINK_LIBRARIES})
set_target_properties(
${CSYNC_LIBRARY}
+164 -32
Ver Arquivo
@@ -96,6 +96,8 @@ static int _data_cmp(const void *key, const void *data) {
int csync_create(CSYNC **csync, const char *local, const char *remote) {
CSYNC *ctx;
size_t len = 0;
char *home;
int rc;
ctx = c_malloc(sizeof(CSYNC));
if (ctx == NULL) {
@@ -127,6 +129,31 @@ int csync_create(CSYNC **csync, const char *local, const char *remote) {
}
ctx->status_code = CSYNC_STATUS_OK;
ctx->options.local_only_mode = false;
ctx->pwd.uid = getuid();
ctx->pwd.euid = geteuid();
home = csync_get_user_home_dir();
if (home == NULL) {
SAFE_FREE(ctx->local.uri);
SAFE_FREE(ctx->remote.uri);
SAFE_FREE(ctx);
errno = ENOMEM;
ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
return -1;
}
rc = asprintf(&ctx->options.config_dir, "%s/%s", home, CSYNC_CONF_DIR);
SAFE_FREE(home);
if (rc < 0) {
SAFE_FREE(ctx->local.uri);
SAFE_FREE(ctx->remote.uri);
SAFE_FREE(ctx);
errno = ENOMEM;
ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
return -1;
}
ctx->local.list = 0;
ctx->remote.list = 0;
@@ -140,6 +167,7 @@ int csync_create(CSYNC **csync, const char *local, const char *remote) {
int csync_init(CSYNC *ctx) {
int rc;
char *config = NULL;
if (ctx == NULL) {
errno = EBADF;
@@ -162,8 +190,12 @@ int csync_init(CSYNC *ctx) {
ctx->local.type = LOCAL_REPLICA;
owncloud_init(ctx);
ctx->remote.type = REMOTE_REPLICA;
if ( !ctx->options.local_only_mode) {
owncloud_init(csync_get_userdata(ctx));
ctx->remote.type = REMOTE_REPLICA;
} else {
ctx->remote.type = LOCAL_REPLICA;
}
if (c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp) < 0) {
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
@@ -177,16 +209,17 @@ int csync_init(CSYNC *ctx) {
goto out;
}
ctx->remote.root_perms = 0;
ctx->status = CSYNC_STATUS_INIT;
csync_set_module_property(ctx, "csync_context", ctx);
/* initialize random generator */
srand(time(NULL));
rc = 0;
out:
SAFE_FREE(config);
return rc;
}
@@ -201,6 +234,7 @@ int csync_update(CSYNC *ctx) {
ctx->status_code = CSYNC_STATUS_OK;
/* create/load statedb */
if (! csync_is_statedb_disabled(ctx)) {
rc = asprintf(&ctx->statedb.file, "%s/.csync_journal.db",
ctx->local.uri);
if (rc < 0) {
@@ -214,6 +248,7 @@ int csync_update(CSYNC *ctx) {
rc = -1;
return rc;
}
}
ctx->status_code = CSYNC_STATUS_OK;
@@ -243,25 +278,27 @@ int csync_update(CSYNC *ctx) {
csync_memstat_check();
/* update detection for remote replica */
csync_gettime(&start);
ctx->current = REMOTE_REPLICA;
ctx->replica = ctx->remote.type;
if( ! ctx->options.local_only_mode ) {
csync_gettime(&start);
ctx->current = REMOTE_REPLICA;
ctx->replica = ctx->remote.type;
rc = csync_ftw(ctx, ctx->remote.uri, csync_walker, MAX_DEPTH);
if (rc < 0) {
if(ctx->status_code == CSYNC_STATUS_OK)
ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_UPDATE_ERROR);
return -1;
rc = csync_ftw(ctx, ctx->remote.uri, csync_walker, MAX_DEPTH);
if (rc < 0) {
if(ctx->status_code == CSYNC_STATUS_OK)
ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_UPDATE_ERROR);
return -1;
}
csync_gettime(&finish);
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
"Update detection for remote replica took %.2f seconds "
"walking %zu files.",
c_secdiff(finish, start), c_rbtree_size(ctx->remote.tree));
csync_memstat_check();
}
csync_gettime(&finish);
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
"Update detection for remote replica took %.2f seconds "
"walking %zu files.",
c_secdiff(finish, start), c_rbtree_size(ctx->remote.tree));
csync_memstat_check();
ctx->status |= CSYNC_STATUS_UPDATE;
return 0;
@@ -394,15 +431,14 @@ static int _csync_treewalk_visitor(void *obj, void *data) {
trav.path = cur->path;
trav.size = cur->size;
trav.modtime = cur->modtime;
trav.uid = cur->uid;
trav.gid = cur->gid;
trav.mode = cur->mode;
trav.type = cur->type;
trav.instruction = cur->instruction;
trav.rename_path = cur->destpath;
trav.etag = cur->etag;
trav.file_id = cur->file_id;
trav.remotePerm = cur->remotePerm;
trav.directDownloadUrl = cur->directDownloadUrl;
trav.directDownloadCookies = cur->directDownloadCookies;
trav.inode = cur->inode;
trav.error_status = cur->error_status;
@@ -425,7 +461,7 @@ static int _csync_treewalk_visitor(void *obj, void *data) {
rc = (*visitor)(&trav, twctx->userdata);
cur->instruction = trav.instruction;
if (trav.etag != cur->etag) { // FIXME It would be nice to have this documented
if (trav.etag != cur->etag) {
SAFE_FREE(cur->etag);
cur->etag = c_strdup(trav.etag);
}
@@ -558,7 +594,6 @@ static void _csync_clean_ctx(CSYNC *ctx)
ctx->local.ignored_cleanup = 0;
SAFE_FREE(ctx->statedb.file);
SAFE_FREE(ctx->remote.root_perms);
}
int csync_commit(CSYNC *ctx) {
@@ -577,7 +612,7 @@ int csync_commit(CSYNC *ctx) {
}
ctx->statedb.db = NULL;
rc = owncloud_commit(ctx);
rc = csync_vio_commit(ctx);
if (rc < 0) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "commit failed: %s",
ctx->error_string ? ctx->error_string : "");
@@ -636,10 +671,9 @@ int csync_destroy(CSYNC *ctx) {
SAFE_FREE(ctx->local.uri);
SAFE_FREE(ctx->remote.uri);
SAFE_FREE(ctx->options.config_dir);
SAFE_FREE(ctx->error_string);
owncloud_destroy(ctx);
#ifdef WITH_ICONV
c_close_iconv();
#endif
@@ -671,6 +705,70 @@ void csync_clear_exclude_list(CSYNC *ctx)
csync_exclude_clear(ctx);
}
const char *csync_get_config_dir(CSYNC *ctx) {
if (ctx == NULL) {
return NULL;
}
return ctx->options.config_dir;
}
int csync_set_config_dir(CSYNC *ctx, const char *path) {
if (ctx == NULL || path == NULL) {
return -1;
}
SAFE_FREE(ctx->options.config_dir);
ctx->options.config_dir = c_strdup(path);
if (ctx->options.config_dir == NULL) {
ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
return -1;
}
return 0;
}
int csync_enable_statedb(CSYNC *ctx) {
if (ctx == NULL) {
return -1;
}
ctx->status_code = CSYNC_STATUS_OK;
if (ctx->status & CSYNC_STATUS_INIT) {
fprintf(stderr, "This function must be called before initialization.");
ctx->status_code = CSYNC_STATUS_CSYNC_STATUS_ERROR;
return -1;
}
ctx->statedb.disabled = 0;
return 0;
}
int csync_disable_statedb(CSYNC *ctx) {
if (ctx == NULL) {
return -1;
}
ctx->status_code = CSYNC_STATUS_OK;
if (ctx->status & CSYNC_STATUS_INIT) {
fprintf(stderr, "This function must be called before initialization.");
ctx->status_code = CSYNC_STATUS_CSYNC_STATUS_ERROR;
return -1;
}
ctx->statedb.disabled = 1;
return 0;
}
int csync_is_statedb_disabled(CSYNC *ctx) {
if (ctx == NULL) {
return -1;
}
return ctx->statedb.disabled;
}
int csync_set_auth_callback(CSYNC *ctx, csync_auth_callback cb) {
if (ctx == NULL || cb == NULL) {
return -1;
@@ -686,6 +784,15 @@ int csync_set_auth_callback(CSYNC *ctx, csync_auth_callback cb) {
return 0;
}
const char *csync_get_statedb_file(CSYNC *ctx) {
if (ctx == NULL) {
return NULL;
}
ctx->status_code = CSYNC_STATUS_OK;
return c_strdup(ctx->statedb.file);
}
void *csync_get_userdata(CSYNC *ctx) {
if (ctx == NULL) {
return NULL;
@@ -729,6 +836,33 @@ CSYNC_STATUS csync_get_status(CSYNC *ctx) {
return ctx->status_code;
}
int csync_set_local_only(CSYNC *ctx, bool local_only) {
if (ctx == NULL) {
return -1;
}
ctx->status_code = CSYNC_STATUS_OK;
if (ctx->status & CSYNC_STATUS_INIT) {
fprintf(stderr, "csync_set_local_only: This function must be called before initialization.");
ctx->status_code = CSYNC_STATUS_CSYNC_STATUS_ERROR;
return -1;
}
ctx->options.local_only_mode=local_only;
return 0;
}
bool csync_get_local_only(CSYNC *ctx) {
if (ctx == NULL) {
return -1;
}
ctx->status_code = CSYNC_STATUS_OK;
return ctx->options.local_only_mode;
}
const char *csync_get_status_string(CSYNC *ctx)
{
return csync_vio_get_status_string(ctx);
@@ -773,8 +907,6 @@ int csync_abort_requested(CSYNC *ctx)
void csync_file_stat_free(csync_file_stat_t *st)
{
if (st) {
SAFE_FREE(st->directDownloadUrl);
SAFE_FREE(st->directDownloadCookies);
SAFE_FREE(st->etag);
SAFE_FREE(st->destpath);
SAFE_FREE(st);
@@ -783,7 +915,7 @@ void csync_file_stat_free(csync_file_stat_t *st)
int csync_set_module_property(CSYNC* ctx, const char* key, void* value)
{
return owncloud_set_property(ctx, key, value);
return csync_vio_set_property(ctx, key, value);
}
+104 -4
Ver Arquivo
@@ -44,6 +44,13 @@
extern "C" {
#endif
/*
* csync file declarations
*/
#define CSYNC_CONF_DIR ".ocsync"
#define CSYNC_CONF_FILE "ocsync.conf"
#define CSYNC_EXCLUDE_FILE "ocsync_exclude.conf"
/**
* Instruction enum. In the file traversal structure, it describes
* the csync state of a file.
@@ -52,7 +59,7 @@ enum csync_status_codes_e {
CSYNC_STATUS_OK = 0,
CSYNC_STATUS_ERROR = 1024, /* don't use this code,
*/
just use in csync_status_ok */
CSYNC_STATUS_UNSUCCESSFUL,
CSYNC_STATUS_NO_LOCK, /* OBSOLETE does not happen anymore */
CSYNC_STATUS_STATEDB_LOAD_ERROR,
@@ -165,6 +172,13 @@ struct csync_tree_walk_file_s {
int64_t size;
int64_t inode;
time_t modtime;
#ifdef _WIN32
uint32_t uid;
uint32_t gid;
#else
uid_t uid;
gid_t gid;
#endif
mode_t mode;
enum csync_ftw_type_e type;
enum csync_instructions_e instruction;
@@ -175,9 +189,6 @@ struct csync_tree_walk_file_s {
const char *rename_path;
const char *etag;
const char *file_id;
const char *remotePerm;
char *directDownloadUrl;
char *directDownloadCookies;
struct {
int64_t size;
time_t modtime;
@@ -203,6 +214,14 @@ typedef void (*csync_log_callback) (int verbosity,
const char *buffer,
void *userdata);
/**
* @brief Check internal csync status.
*
* @param csync The context to check.
*
* @return true if status is error free, false for error states.
*/
bool csync_status_ok(CSYNC *ctx);
/**
* @brief Allocate a csync context.
@@ -314,6 +333,62 @@ int csync_add_exclude_list(CSYNC *ctx, const char *path);
*/
void csync_clear_exclude_list(CSYNC *ctx);
/**
* @brief Get the config directory.
*
* @param ctx The csync context.
*
* @return The path of the config directory or NULL on error.
*/
const char *csync_get_config_dir(CSYNC *ctx);
/**
* @brief Change the config directory.
*
* @param ctx The csync context.
*
* @param path The path to the new config directory.
*
* @return 0 on success, less than 0 if an error occured.
*/
int csync_set_config_dir(CSYNC *ctx, const char *path);
/**
* @brief Remove the complete config directory.
*
* @param ctx The csync context.
*
* @return 0 on success, less than 0 if an error occured.
*/
int csync_remove_config_dir(CSYNC *ctx);
/**
* @brief Enable the usage of the statedb. It is enabled by default.
*
* @param ctx The csync context.
*
* @return 0 on success, less than 0 if an error occured.
*/
int csync_enable_statedb(CSYNC *ctx);
/**
* @brief Disable the usage of the statedb. It is enabled by default.
*
* @param ctx The csync context.
*
* @return 0 on success, less than 0 if an error occured.
*/
int csync_disable_statedb(CSYNC *ctx);
/**
* @brief Check if the statedb usage is enabled.
*
* @param ctx The csync context.
*
* @return 1 if it is enabled, 0 if it is disabled.
*/
int csync_is_statedb_disabled(CSYNC *ctx);
/**
* @brief Get the userdata saved in the context.
*
@@ -406,6 +481,31 @@ void *csync_get_log_userdata(void);
*/
int csync_set_log_userdata(void *data);
/**
* @brief Get the path of the statedb file used.
*
* @param ctx The csync context.
*
* @return The path to the statedb file, NULL if an error occured.
*/
const char *csync_get_statedb_file(CSYNC *ctx);
/**
* @brief Flag to tell csync that only a local run is intended. Call before csync_init
*
* @param local_only Bool flag to indicate local only mode.
*
* @return 0 on success, less than 0 if an error occured.
*/
int csync_set_local_only( CSYNC *ctx, bool local_only );
/**
* @brief Retrieve the flag to tell csync that only a local run is intended.
*
* @return 1: stay local only, 0: local and remote mode
*/
bool csync_get_local_only( CSYNC *ctx );
/* Used for special modes or debugging */
CSYNC_STATUS csync_get_status(CSYNC *ctx);
+1 -7
Ver Arquivo
@@ -20,18 +20,12 @@
#include "config_csync.h"
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "c_lib.h"
#include "c_private.h"
#include "csync_private.h"
#include "csync_exclude.h"
@@ -223,7 +217,7 @@ CSYNC_EXCLUDE_TYPE csync_excluded(CSYNC *ctx, const char *path, int filetype) {
SAFE_FREE(bname);
SAFE_FREE(dname);
if (ctx == NULL || ctx->excludes == NULL) {
if (ctx->excludes == NULL) {
goto out;
}
+46
Ver Arquivo
@@ -47,6 +47,52 @@
#include "csync_macros.h"
#include "csync_log.h"
#ifdef _WIN32
char *csync_get_user_home_dir(void) {
wchar_t tmp[MAX_PATH];
char *szPath = NULL;
if( SHGetFolderPathW( NULL,
CSIDL_PROFILE|CSIDL_FLAG_CREATE,
NULL,
0,
tmp) == S_OK ) {
szPath = c_utf8_from_locale(tmp);
return szPath;
}
return NULL;
}
#else /* ************* !WIN32 ************ */
#ifndef NSS_BUFLEN_PASSWD
#define NSS_BUFLEN_PASSWD 4096
#endif /* NSS_BUFLEN_PASSWD */
char *csync_get_user_home_dir(void) {
const char *envp;
struct passwd pwd;
struct passwd *pwdbuf;
char buf[NSS_BUFLEN_PASSWD];
int rc;
envp = getenv("HOME");
if (envp != NULL && envp[0] != '\0') {
return c_strdup(envp);
}
/* Still nothing found, read the password file */
rc = getpwuid_r(getuid(), &pwd, buf, NSS_BUFLEN_PASSWD, &pwdbuf);
if (rc != 0) {
return c_strdup(pwd.pw_dir);
}
return NULL;
}
#endif /* ************* WIN32 ************ */
#ifdef HAVE_FNMATCH
#include <fnmatch.h>
+2
Ver Arquivo
@@ -35,6 +35,8 @@
#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */
#endif
char *csync_get_user_home_dir(void);
int csync_fnmatch(__const char *__pattern, __const char *__name, int __flags);
/**
+400 -165
Ver Arquivo
@@ -20,10 +20,79 @@
*/
#include "csync_owncloud.h"
#include "csync_owncloud_private.h"
#include <inttypes.h>
/*
* free the fetchCtx
*/
static void free_fetchCtx( struct listdir_context *ctx )
{
struct resource *newres, *res;
if( ! ctx ) return;
newres = ctx->list;
res = newres;
ctx->ref--;
if (ctx->ref > 0) return;
SAFE_FREE(ctx->target);
while( res ) {
SAFE_FREE(res->uri);
SAFE_FREE(res->name);
SAFE_FREE(res->md5);
memset( res->file_id, 0, FILE_ID_BUF_SIZE+1 );
newres = res->next;
SAFE_FREE(res);
res = newres;
}
SAFE_FREE(ctx);
}
/*
* local variables.
*/
struct dav_session_s dav_session; /* The DAV Session, initialised in dav_connect */
int _connected = 0; /* flag to indicate if a connection exists, ie.
the dav_session is valid */
void *_userdata;
long long chunked_total_size = 0;
long long chunked_done = 0;
struct listdir_context *propfind_cache = 0;
bool is_first_propfind = true;
csync_vio_file_stat_t _stat_cache;
/* id cache, cache the ETag: header of a GET request */
struct { char *uri; char *id; } _id_cache = { NULL, NULL };
static void clean_caches() {
clear_propfind_recursive_cache();
free_fetchCtx(propfind_cache);
propfind_cache = NULL;
SAFE_FREE(_stat_cache.name);
SAFE_FREE(_stat_cache.etag );
memset( _stat_cache.file_id, 0, FILE_ID_BUF_SIZE+1 );
SAFE_FREE(_id_cache.uri);
SAFE_FREE(_id_cache.id);
}
#define PUT_BUFFER_SIZE 1024*5
char _buffer[PUT_BUFFER_SIZE];
/*
* helper method to build up a user text for SSL problems, called from the
@@ -47,7 +116,7 @@ static void addSSLWarning( char *ptr, const char *warn, int len )
* it to the csync callback to ask the user.
*/
#define LEN 4096
static int ssl_callback_by_neon(void *userdata, int failures,
static int verify_sslcert(void *userdata, int failures,
const ne_ssl_certificate *certificate)
{
char problem[LEN];
@@ -55,8 +124,8 @@ static int ssl_callback_by_neon(void *userdata, int failures,
int ret = -1;
const ne_ssl_certificate *cert = certificate;
csync_auth_callback authcb = NULL;
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
(void) userdata;
memset( problem, 0, LEN );
while( cert ) {
@@ -92,14 +161,14 @@ static int ssl_callback_by_neon(void *userdata, int failures,
}
addSSLWarning( problem, "Do you want to accept the certificate chain anyway?\nAnswer yes to do so and take the risk: ", LEN );
if( ctx->csync_ctx ) {
authcb = csync_get_auth_callback( ctx->csync_ctx );
if( dav_session.csync_ctx ) {
authcb = csync_get_auth_callback( dav_session.csync_ctx );
}
if( authcb ){
/* call the csync callback */
DEBUG_WEBDAV("Call the csync callback for SSL problems");
memset( buf, 0, NE_ABUFSIZ );
(*authcb) ( problem, buf, NE_ABUFSIZ-1, 1, 0, csync_get_userdata(ctx->csync_ctx) );
(*authcb) ( problem, buf, NE_ABUFSIZ-1, 1, 0, _userdata );
if( buf[0] == 'y' || buf[0] == 'Y') {
ret = 0;
} else {
@@ -115,39 +184,41 @@ static int ssl_callback_by_neon(void *userdata, int failures,
* Authentication callback. Is set by ne_set_server_auth to be called
* from the neon lib to authenticate a request.
*/
static int authentication_callback_by_neon( void *userdata, const char *realm, int attempt,
static int ne_auth( void *userdata, const char *realm, int attempt,
char *username, char *password)
{
char buf[NE_ABUFSIZ];
csync_auth_callback authcb = NULL;
int re = attempt;
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
(void) userdata;
(void) realm;
/* DEBUG_WEBDAV( "Authentication required %s", realm ); */
if( username && password ) {
DEBUG_WEBDAV( "Authentication required %s", username );
if( ctx->dav_session.user ) {
if( dav_session.user ) {
/* allow user without password */
if( strlen( ctx->dav_session.user ) < NE_ABUFSIZ ) {
strcpy( username, ctx->dav_session.user );
if( strlen( dav_session.user ) < NE_ABUFSIZ ) {
strcpy( username, dav_session.user );
}
if( ctx->dav_session.pwd && strlen( ctx->dav_session.pwd ) < NE_ABUFSIZ ) {
strcpy( password, ctx->dav_session.pwd );
if( dav_session.pwd && strlen( dav_session.pwd ) < NE_ABUFSIZ ) {
strcpy( password, dav_session.pwd );
}
} else {
authcb = csync_get_auth_callback( ctx->csync_ctx );
if( dav_session.csync_ctx ) {
authcb = csync_get_auth_callback( dav_session.csync_ctx );
}
if( authcb != NULL ){
/* call the csync callback */
DEBUG_WEBDAV("Call the csync callback for %s", realm );
memset( buf, 0, NE_ABUFSIZ );
(*authcb) ("Enter your username: ", buf, NE_ABUFSIZ-1, 1, 0, csync_get_userdata(ctx->csync_ctx) );
(*authcb) ("Enter your username: ", buf, NE_ABUFSIZ-1, 1, 0, _userdata );
if( strlen(buf) < NE_ABUFSIZ ) {
strcpy( username, buf );
}
memset( buf, 0, NE_ABUFSIZ );
(*authcb) ("Enter your password: ", buf, NE_ABUFSIZ-1, 0, 0, csync_get_userdata(ctx->csync_ctx) );
(*authcb) ("Enter your password: ", buf, NE_ABUFSIZ-1, 0, 0, _userdata );
if( strlen(buf) < NE_ABUFSIZ) {
strcpy( password, buf );
}
@@ -164,15 +235,15 @@ static int authentication_callback_by_neon( void *userdata, const char *realm, i
* from the neon lib to authenticate against a proxy. The data to authenticate
* against comes from mirall throught vio_module_init function.
*/
static int proxy_authentication_callback_by_neon( void *userdata, const char *realm, int attempt,
static int ne_proxy_auth( void *userdata, const char *realm, int attempt,
char *username, char *password)
{
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
(void) userdata;
(void) realm;
if( ctx->dav_session.proxy_user && strlen( ctx->dav_session.proxy_user ) < NE_ABUFSIZ) {
strcpy( username, ctx->dav_session.proxy_user );
if( ctx->dav_session.proxy_pwd && strlen( ctx->dav_session.proxy_pwd ) < NE_ABUFSIZ) {
strcpy( password, ctx->dav_session.proxy_pwd );
if( dav_session.proxy_user && strlen( dav_session.proxy_user ) < NE_ABUFSIZ) {
strcpy( username, dav_session.proxy_user );
if( dav_session.proxy_pwd && strlen( dav_session.proxy_pwd ) < NE_ABUFSIZ) {
strcpy( password, dav_session.proxy_pwd );
}
}
/* NTLM needs several attempts */
@@ -180,42 +251,42 @@ static int proxy_authentication_callback_by_neon( void *userdata, const char *re
}
/* Configure the proxy depending on the variables */
static int configureProxy( csync_owncloud_ctx_t *ctx, ne_session *session )
static int configureProxy( ne_session *session )
{
int port = 8080;
int re = -1;
if( ! session ) return -1;
if( ! ctx->dav_session.proxy_type ) return 0; /* Go by NoProxy per default */
if( ! dav_session.proxy_type ) return 0; /* Go by NoProxy per default */
if( ctx->dav_session.proxy_port > 0 ) {
port = ctx->dav_session.proxy_port;
if( dav_session.proxy_port > 0 ) {
port = dav_session.proxy_port;
}
if( c_streq(ctx->dav_session.proxy_type, "NoProxy" )) {
if( c_streq(dav_session.proxy_type, "NoProxy" )) {
DEBUG_WEBDAV("No proxy configured.");
re = 0;
} else if( c_streq(ctx->dav_session.proxy_type, "DefaultProxy") ||
c_streq(ctx->dav_session.proxy_type, "HttpProxy") ||
c_streq(ctx->dav_session.proxy_type, "HttpCachingProxy") ||
c_streq(ctx->dav_session.proxy_type, "Socks5Proxy")) {
} else if( c_streq(dav_session.proxy_type, "DefaultProxy") ||
c_streq(dav_session.proxy_type, "HttpProxy") ||
c_streq(dav_session.proxy_type, "HttpCachingProxy") ||
c_streq(dav_session.proxy_type, "Socks5Proxy")) {
if( ctx->dav_session.proxy_host ) {
DEBUG_WEBDAV("%s at %s:%d", ctx->dav_session.proxy_type, ctx->dav_session.proxy_host, port );
if (c_streq(ctx->dav_session.proxy_type, "Socks5Proxy")) {
ne_session_socks_proxy(session, NE_SOCK_SOCKSV5, ctx->dav_session.proxy_host, port,
ctx->dav_session.proxy_user, ctx->dav_session.proxy_pwd);
if( dav_session.proxy_host ) {
DEBUG_WEBDAV("%s at %s:%d", dav_session.proxy_type, dav_session.proxy_host, port );
if (c_streq(dav_session.proxy_type, "Socks5Proxy")) {
ne_session_socks_proxy(session, NE_SOCK_SOCKSV5, dav_session.proxy_host, port,
dav_session.proxy_user, dav_session.proxy_pwd);
} else {
ne_session_proxy(session, ctx->dav_session.proxy_host, port );
ne_session_proxy(session, dav_session.proxy_host, port );
}
re = 2;
} else {
DEBUG_WEBDAV("%s requested but no proxy host defined.", ctx->dav_session.proxy_type );
DEBUG_WEBDAV("%s requested but no proxy host defined.", dav_session.proxy_type );
/* we used to try ne_system_session_proxy here, but we should rather err out
to behave exactly like the caller. */
}
} else {
DEBUG_WEBDAV( "Unsupported Proxy: %s", ctx->dav_session.proxy_type );
DEBUG_WEBDAV( "Unsupported Proxy: %s", dav_session.proxy_type );
}
return re;
@@ -232,9 +303,9 @@ static void post_request_hook(ne_request *req, void *userdata, const ne_status *
const char *sc = NULL;
char *key = NULL;
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
(void) userdata;
if (ctx->dav_session.session_key)
if (dav_session.session_key)
return; /* We already have a session cookie, and we should ignore other ones */
if(!(status && req)) return;
@@ -302,8 +373,8 @@ static void post_request_hook(ne_request *req, void *userdata, const ne_status *
}
if( key ) {
DEBUG_WEBDAV("----> Session-key: %s", key);
SAFE_FREE(ctx->dav_session.session_key);
ctx->dav_session.session_key = key;
SAFE_FREE(dav_session.session_key);
dav_session.session_key = key;
}
}
@@ -314,14 +385,13 @@ static void post_request_hook(ne_request *req, void *userdata, const ne_status *
static void request_created_hook(ne_request *req, void *userdata,
const char *method, const char *requri)
{
// FIXME Can possibly be merged with pre_send_hook
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t *) userdata;
(void) userdata;
(void) method;
(void) requri;
if( !req ) return;
if(ctx->dav_session.proxy_type) {
if(dav_session.proxy_type) {
/* required for NTLM */
ne_add_request_header(req, "Proxy-Connection", "Keep-Alive");
}
@@ -334,12 +404,12 @@ static void request_created_hook(ne_request *req, void *userdata,
static void pre_send_hook(ne_request *req, void *userdata,
ne_buffer *header)
{
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t *) userdata;
(void) userdata;
if( !req ) return;
if(ctx->dav_session.session_key) {
ne_buffer_concat(header, "Cookie: ", ctx->dav_session.session_key, "\r\n", NULL);
if(dav_session.session_key) {
ne_buffer_concat(header, "Cookie: ", dav_session.session_key, "\r\n", NULL);
} else {
DEBUG_WEBDAV("csync pre_send_hook We don't have a Auth Cookie (session_key), this is wrong!");
}
@@ -349,15 +419,16 @@ static int post_send_hook(ne_request *req, void *userdata,
const ne_status *status)
{
const char *location;
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t *) userdata;
(void) userdata;
(void) status;
location = ne_get_response_header(req, "Location");
if( !location ) return NE_OK;
if( ctx->dav_session.redir_callback ) {
if( ctx->dav_session.redir_callback( ctx->csync_ctx, location ) ) {
if( dav_session.redir_callback ) {
if( dav_session.redir_callback( dav_session.csync_ctx, location ) ) {
return NE_REDIRECT;
} else {
return NE_RETRY;
@@ -367,12 +438,37 @@ static int post_send_hook(ne_request *req, void *userdata,
return NE_REDIRECT;
}
// as per http://sourceforge.net/p/predef/wiki/OperatingSystems/
// extend as required
static const char* get_platform() {
#if defined (_WIN32)
return "Windows";
#elif defined(__APPLE__)
return "Macintosh";
#elif defined(__gnu_linux__)
return "Linux";
#elif defined(__DragonFly__)
/* might also define __FreeBSD__ */
return "DragonFlyBSD";
#elif defined(__FreeBSD__)
return "FreeBSD";
#elif defined(__NetBSD__)
return "NetBSD";
#elif defined(__OpenBSD__)
return "OpenBSD";
#elif defined(sun) || defined(__sun)
return "Solaris";
#else
return "Unknown OS";
#endif
}
/*
* Connect to a DAV server
* This function sets the flag _connected if the connection is established
* and returns if the flag is set, so calling it frequently is save.
*/
static int dav_connect(csync_owncloud_ctx_t *ctx, const char *base_url) {
static int dav_connect(const char *base_url) {
int useSSL = 0;
int rc;
char protocol[6] = {'\0'};
@@ -383,14 +479,11 @@ static int dav_connect(csync_owncloud_ctx_t *ctx, const char *base_url) {
unsigned int port = 0;
int proxystate = -1;
if (ctx->_connected) {
if (_connected) {
return 0;
}
rc = c_parse_uri( base_url, &scheme,
&ctx->dav_session.user,
&ctx->dav_session.pwd,
&host, &port, &path );
rc = c_parse_uri( base_url, &scheme, &dav_session.user, &dav_session.pwd, &host, &port, &path );
if( rc < 0 ) {
DEBUG_WEBDAV("Failed to parse uri %s", base_url );
goto out;
@@ -412,29 +505,29 @@ static int dav_connect(csync_owncloud_ctx_t *ctx, const char *base_url) {
goto out;
}
DEBUG_WEBDAV("* user %s", ctx->dav_session.user ? ctx->dav_session.user : "");
DEBUG_WEBDAV("* user %s", dav_session.user ? dav_session.user : "");
if (port == 0) {
port = ne_uri_defaultport(protocol);
}
ctx->dav_session.ctx = ne_session_create( protocol, host, port);
dav_session.ctx = ne_session_create( protocol, host, port);
if (ctx->dav_session.ctx == NULL) {
if (dav_session.ctx == NULL) {
DEBUG_WEBDAV("Session create with protocol %s failed", protocol );
rc = -1;
goto out;
}
if (ctx->dav_session.read_timeout != 0) {
ne_set_read_timeout(ctx->dav_session.ctx, ctx->dav_session.read_timeout);
DEBUG_WEBDAV("Timeout set to %u seconds", ctx->dav_session.read_timeout );
if (dav_session.read_timeout != 0) {
ne_set_read_timeout(dav_session.ctx, dav_session.read_timeout);
DEBUG_WEBDAV("Timeout set to %u seconds", dav_session.read_timeout );
}
snprintf( uaBuf, sizeof(uaBuf), "Mozilla/5.0 (%s) csyncoC/%s",
csync_owncloud_get_platform(), CSYNC_STRINGIFY( LIBCSYNC_VERSION ));
ne_set_useragent( ctx->dav_session.ctx, uaBuf);
ne_set_server_auth(ctx->dav_session.ctx, authentication_callback_by_neon, ctx);
get_platform(), CSYNC_STRINGIFY( LIBCSYNC_VERSION ));
ne_set_useragent( dav_session.ctx, uaBuf);
ne_set_server_auth(dav_session.ctx, ne_auth, 0 );
if( useSSL ) {
if (!ne_has_support(NE_FEATURE_SSL)) {
@@ -443,28 +536,28 @@ static int dav_connect(csync_owncloud_ctx_t *ctx, const char *base_url) {
goto out;
}
ne_ssl_trust_default_ca( ctx->dav_session.ctx );
ne_ssl_set_verify( ctx->dav_session.ctx, ssl_callback_by_neon, ctx);
ne_ssl_trust_default_ca( dav_session.ctx );
ne_ssl_set_verify( dav_session.ctx, verify_sslcert, 0 );
}
/* Hook called when a request is created. It sets the proxy connection header. */
ne_hook_create_request( ctx->dav_session.ctx, request_created_hook, ctx );
ne_hook_create_request( dav_session.ctx, request_created_hook, NULL );
/* Hook called after response headers are read. It gets the Session ID. */
ne_hook_post_headers( ctx->dav_session.ctx, post_request_hook, ctx );
ne_hook_post_headers( dav_session.ctx, post_request_hook, NULL );
/* Hook called before a request is sent. It sets the cookies. */
ne_hook_pre_send( ctx->dav_session.ctx, pre_send_hook, ctx );
ne_hook_pre_send( dav_session.ctx, pre_send_hook, NULL );
/* Hook called after request is dispatched. Used for handling possible redirections. */
ne_hook_post_send( ctx->dav_session.ctx, post_send_hook, ctx );
ne_hook_post_send( dav_session.ctx, post_send_hook, NULL );
/* Proxy support */
proxystate = configureProxy( ctx, ctx->dav_session.ctx );
proxystate = configureProxy( dav_session.ctx );
if( proxystate < 0 ) {
DEBUG_WEBDAV("Error: Proxy-Configuration failed.");
} else if( proxystate > 0 ) {
ne_set_proxy_auth( ctx->dav_session.ctx, proxy_authentication_callback_by_neon, ctx );
ne_set_proxy_auth( dav_session.ctx, ne_proxy_auth, 0 );
}
ctx->_connected = 1;
_connected = 1;
rc = 0;
out:
SAFE_FREE(path);
@@ -480,16 +573,24 @@ out:
* and fills a resource struct and stores it to the result list which
* is stored in the listdir_context.
*/
static void propfind_results_callback(void *userdata,
static void results(void *userdata,
const ne_uri *uri,
const ne_prop_result_set *set)
{
struct listdir_context *fetchCtx = userdata;
struct resource *newres = 0;
const char *clength, *modtime = NULL;
const char *resourcetype = NULL;
const char *md5sum = NULL;
const char *file_id = NULL;
const ne_status *status = NULL;
char *path = ne_path_unescape( uri->path );
(void) status;
if( ! fetchCtx ) {
DEBUG_WEBDAV("No valid fetchContext");
return;
}
if( ! fetchCtx->target ) {
DEBUG_WEBDAV("error: target must not be zero!" );
@@ -498,9 +599,37 @@ static void propfind_results_callback(void *userdata,
/* Fill the resource structure with the data about the file */
newres = c_malloc(sizeof(struct resource));
ZERO_STRUCTP(newres);
newres->uri = path; /* no need to strdup because ne_path_unescape already allocates */
newres->name = c_basename( path );
fill_webdav_properties_into_resource(newres, set);
modtime = ne_propset_value( set, &ls_props[0] );
clength = ne_propset_value( set, &ls_props[1] );
resourcetype = ne_propset_value( set, &ls_props[2] );
md5sum = ne_propset_value( set, &ls_props[3] );
file_id = ne_propset_value( set, &ls_props[4] );
newres->type = resr_normal;
if( clength == NULL && resourcetype && strncmp( resourcetype, "<DAV:collection>", 16 ) == 0) {
newres->type = resr_collection;
}
if (modtime) {
newres->modtime = oc_httpdate_parse(modtime);
}
/* DEBUG_WEBDAV("Parsing Modtime: %s -> %llu", modtime, (unsigned long long) newres->modtime ); */
newres->size = 0;
if (clength) {
newres->size = atoll(clength);
/* DEBUG_WEBDAV("Parsed File size for %s from %s: %lld", newres->name, clength, (long long)newres->size ); */
}
if( md5sum ) {
newres->md5 = csync_normalize_etag(md5sum);
}
csync_vio_set_file_id(newres->file_id, file_id);
/* prepend the new resource to the result list */
newres->next = fetchCtx->list;
@@ -514,7 +643,7 @@ static void propfind_results_callback(void *userdata,
/*
* fetches a resource list from the WebDAV server. This is equivalent to list dir.
*/
static struct listdir_context *fetch_resource_list(csync_owncloud_ctx_t *ctx, const char *uri, int depth)
static struct listdir_context *fetch_resource_list(const char *uri, int depth)
{
struct listdir_context *fetchCtx;
int ret = 0;
@@ -528,12 +657,12 @@ static struct listdir_context *fetch_resource_list(csync_owncloud_ctx_t *ctx, co
/* The old legacy one-level PROPFIND cache. Also gets filled
by the recursive cache if 'infinity' did not suceed. */
if (ctx->propfind_cache) {
if (c_streq(curi, ctx->propfind_cache->target)) {
if (propfind_cache) {
if (c_streq(curi, propfind_cache->target)) {
DEBUG_WEBDAV("fetch_resource_list Using simple PROPFIND cache %s", curi);
ctx->propfind_cache->ref++;
propfind_cache->ref++;
SAFE_FREE(curi);
return ctx->propfind_cache;
return propfind_cache;
}
}
@@ -549,10 +678,10 @@ static struct listdir_context *fetch_resource_list(csync_owncloud_ctx_t *ctx, co
fetchCtx->ref = 1;
/* do a propfind request and parse the results in the results function, set as callback */
hdl = ne_propfind_create(ctx->dav_session.ctx, curi, depth);
hdl = ne_propfind_create(dav_session.ctx, curi, depth);
if(hdl) {
ret = ne_propfind_named(hdl, ls_props, propfind_results_callback, fetchCtx);
ret = ne_propfind_named(hdl, ls_props, results, fetchCtx);
request = ne_propfind_get_request( hdl );
req_status = ne_get_status( request );
}
@@ -565,14 +694,14 @@ static struct listdir_context *fetch_resource_list(csync_owncloud_ctx_t *ctx, co
DEBUG_WEBDAV("ERROR: Request failed: status %d (%s)", req_status->code,
req_status->reason_phrase);
ret = NE_CONNECT;
set_error_message(ctx, req_status->reason_phrase);
set_error_message(req_status->reason_phrase);
}
DEBUG_WEBDAV("Simple propfind result code %d.", req_status ? req_status->code : -1);
} else {
if( ret == NE_ERROR && req_status->code == 404) {
errno = ENOENT;
} else {
set_errno_from_neon_errcode(ctx, ret);
set_errno_from_neon_errcode(ret);
}
}
@@ -587,18 +716,18 @@ static struct listdir_context *fetch_resource_list(csync_owncloud_ctx_t *ctx, co
DEBUG_WEBDAV("ERROR: Content type of propfind request not XML: %s.",
content_type ? content_type: "<empty>");
errno = ERRNO_WRONG_CONTENT;
set_error_message(ctx, "Server error: PROPFIND reply is not XML formatted!");
set_error_message("Server error: PROPFIND reply is not XML formatted!");
ret = NE_CONNECT;
}
}
if( ret != NE_OK ) {
const char *err = NULL;
set_errno_from_neon_errcode(ctx, ret);
set_errno_from_neon_errcode(ret);
err = ne_get_error( ctx->dav_session.ctx );
err = ne_get_error( dav_session.ctx );
if(err) {
set_error_message(ctx, err);
set_error_message(err);
}
DEBUG_WEBDAV("WRN: propfind named failed with %d, request error: %s", ret, err ? err : "<nil>");
}
@@ -611,19 +740,19 @@ static struct listdir_context *fetch_resource_list(csync_owncloud_ctx_t *ctx, co
return NULL;
}
free_fetchCtx(ctx->propfind_cache);
ctx->propfind_cache = fetchCtx;
ctx->propfind_cache->ref++;
free_fetchCtx(propfind_cache);
propfind_cache = fetchCtx;
propfind_cache->ref++;
return fetchCtx;
}
static struct listdir_context *fetch_resource_list_attempts(csync_owncloud_ctx_t *ctx, const char *uri, int depth)
static struct listdir_context *fetch_resource_list_attempts(const char *uri, int depth)
{
int i;
struct listdir_context *fetchCtx = NULL;
for(i = 0; i < 10; ++i) {
fetchCtx = fetch_resource_list(ctx, uri, depth);
fetchCtx = fetch_resource_list(uri, depth);
if(fetchCtx) break;
/* only loop in case the content is not XML formatted. Otherwise for every
* non successful stat (for non existing directories) its tried 10 times. */
@@ -635,39 +764,165 @@ static struct listdir_context *fetch_resource_list_attempts(csync_owncloud_ctx_t
return fetchCtx;
}
static void fill_stat_cache( csync_vio_file_stat_t *lfs ) {
if( _stat_cache.name ) SAFE_FREE(_stat_cache.name);
if( _stat_cache.etag ) SAFE_FREE(_stat_cache.etag );
if( !lfs) return;
_stat_cache.name = c_strdup(lfs->name);
_stat_cache.mtime = lfs->mtime;
_stat_cache.fields = lfs->fields;
_stat_cache.type = lfs->type;
_stat_cache.size = lfs->size;
csync_vio_file_stat_set_file_id(&_stat_cache, lfs->file_id);
if( lfs->etag ) {
_stat_cache.etag = c_strdup(lfs->etag);
}
}
/*
* file functions
*/
int owncloud_stat(const char *uri, csync_vio_file_stat_t *buf) {
/* get props:
* modtime
* creattime
* size
*/
csync_vio_file_stat_t *lfs = NULL;
struct listdir_context *fetchCtx = NULL;
char *decodedUri = NULL;
int len = 0;
errno = 0;
buf->name = c_basename(uri);
if (buf->name == NULL) {
errno = ENOMEM;
return -1;
}
if( _stat_cache.name && strcmp( buf->name, _stat_cache.name ) == 0 ) {
buf->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS;
buf->fields = _stat_cache.fields;
buf->type = _stat_cache.type;
buf->mtime = _stat_cache.mtime;
buf->size = _stat_cache.size;
buf->mode = _stat_perms( _stat_cache.type );
buf->etag = NULL;
if( _stat_cache.etag ) {
buf->etag = c_strdup( _stat_cache.etag );
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ETAG;
}
csync_vio_file_stat_set_file_id( buf, _stat_cache.file_id );
return 0;
}
DEBUG_WEBDAV("owncloud_stat => Could not find in stat cache %s", uri);
/* fetch data via a propfind call. */
/* fetchCtx = fetch_resource_list( uri, NE_DEPTH_ONE); */
fetchCtx = fetch_resource_list_attempts( uri, NE_DEPTH_ONE);
DEBUG_WEBDAV("=> Errno after fetch resource list for %s: %d", uri, errno);
if (!fetchCtx) {
return -1;
}
if( fetchCtx ) {
struct resource *res = fetchCtx->list;
while( res ) {
/* remove trailing slashes */
len = strlen(res->uri);
while( len > 0 && res->uri[len-1] == '/' ) --len;
decodedUri = ne_path_unescape( fetchCtx->target ); /* allocates memory */
/* Only do the comparaison of the part of the string without the trailing
slashes, and make sure decodedUri is not too large */
if( strncmp(res->uri, decodedUri, len ) == 0 && decodedUri[len] == '\0') {
SAFE_FREE( decodedUri );
break;
}
res = res->next;
SAFE_FREE( decodedUri );
}
if( res ) {
DEBUG_WEBDAV("Working on file %s", res->name );
} else {
DEBUG_WEBDAV("ERROR: Result struct not valid!");
}
lfs = resourceToFileStat( res );
if( lfs ) {
buf->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ETAG;
buf->fields = lfs->fields;
buf->type = lfs->type;
buf->mtime = lfs->mtime;
buf->size = lfs->size;
buf->mode = _stat_perms( lfs->type );
buf->etag = NULL;
if( lfs->etag ) {
buf->etag = c_strdup( lfs->etag );
}
csync_vio_file_stat_set_file_id( buf, lfs->file_id );
/* fill the static stat buf as input for the stat function */
csync_vio_file_stat_destroy( lfs );
}
free_fetchCtx( fetchCtx );
}
DEBUG_WEBDAV("STAT result from propfind: %s, mtime: %llu", buf->name ? buf->name:"NULL",
(unsigned long long) buf->mtime );
return 0;
}
/*
* directory functions
*/
csync_vio_handle_t *owncloud_opendir(CSYNC *ctx, const char *uri) {
csync_vio_handle_t *owncloud_opendir(const char *uri) {
struct listdir_context *fetchCtx = NULL;
char *curi = NULL;
DEBUG_WEBDAV("opendir method called on %s", uri );
if (dav_connect( ctx->owncloud_context, uri ) < 0) {
if (dav_connect( uri ) < 0) {
DEBUG_WEBDAV("connection failed");
return NULL;
}
curi = _cleanPath( uri );
if (ctx->owncloud_context->is_first_propfind && !ctx->owncloud_context->dav_session.no_recursive_propfind) {
ctx->owncloud_context->is_first_propfind = false;
if (is_first_propfind && !dav_session.no_recursive_propfind) {
is_first_propfind = false;
// Try to fill it
fill_recursive_propfind_cache(ctx->owncloud_context, uri, curi);
fill_recursive_propfind_cache(uri, curi);
}
if (ctx->owncloud_context->propfind_recursive_cache) {
if (propfind_recursive_cache) {
// Try to fetch from recursive cache (if we have one)
fetchCtx = get_listdir_context_from_recursive_cache(ctx->owncloud_context, curi);
fetchCtx = get_listdir_context_from_recursive_cache(curi);
}
SAFE_FREE(curi);
ctx->owncloud_context->is_first_propfind = false;
is_first_propfind = false;
if (fetchCtx) {
return fetchCtx;
}
/* fetchCtx = fetch_resource_list( uri, NE_DEPTH_ONE ); */
fetchCtx = fetch_resource_list_attempts( ctx->owncloud_context, uri, NE_DEPTH_ONE);
fetchCtx = fetch_resource_list_attempts( uri, NE_DEPTH_ONE);
if( !fetchCtx ) {
/* errno is set properly in fetch_resource_list */
DEBUG_WEBDAV("Errno set to %d", errno);
@@ -680,16 +935,17 @@ csync_vio_handle_t *owncloud_opendir(CSYNC *ctx, const char *uri) {
/* no freeing of curi because its part of the fetchCtx and gets freed later */
}
int owncloud_closedir(CSYNC *ctx, csync_vio_handle_t *dhandle) {
int owncloud_closedir(csync_vio_handle_t *dhandle) {
struct listdir_context *fetchCtx = dhandle;
free_fetchCtx(fetchCtx);
(void)ctx;
return 0;
}
csync_vio_file_stat_t *owncloud_readdir(CSYNC *ctx, csync_vio_handle_t *dhandle) {
csync_vio_file_stat_t *owncloud_readdir(csync_vio_handle_t *dhandle) {
struct listdir_context *fetchCtx = dhandle;
(void)ctx;
// DEBUG_WEBDAV("owncloud_readdir" );
// DEBUG_WEBDAV("owncloud_readdir %s ", fetchCtx->target);
@@ -715,20 +971,10 @@ csync_vio_file_stat_t *owncloud_readdir(CSYNC *ctx, csync_vio_handle_t *dhandle)
*/
escaped_path = ne_path_escape( currResource->uri );
if (ne_path_compare(fetchCtx->target, escaped_path) != 0) {
// Convert the resource for the caller
csync_vio_file_stat_t* lfs = csync_vio_file_stat_new();
resourceToFileStat(lfs, currResource);
csync_vio_file_stat_t* lfs = resourceToFileStat(currResource);
fill_stat_cache(lfs);
SAFE_FREE( escaped_path );
return lfs;
} else {
/* The first item is the root item, memorize its permissions */
if (!ctx->remote.root_perms) {
if (strlen(currResource->remotePerm) > 0) {
/* Only copy if permissions contain something. Empty string means server didn't return them */
ctx->remote.root_perms = c_strdup(currResource->remotePerm);
}
}
}
/* This is the target URI */
@@ -738,55 +984,39 @@ csync_vio_file_stat_t *owncloud_readdir(CSYNC *ctx, csync_vio_handle_t *dhandle)
return NULL;
}
char *owncloud_error_string(CSYNC* ctx)
char *owncloud_error_string(void)
{
return ctx->owncloud_context->dav_session.error_string;
return dav_session.error_string;
}
int owncloud_commit(CSYNC* ctx) {
if (!ctx->owncloud_context) {
return 0;
}
int owncloud_commit(void) {
clear_propfind_recursive_cache(ctx->owncloud_context);
clean_caches();
free_fetchCtx(ctx->owncloud_context->propfind_cache);
ctx->owncloud_context->propfind_cache = NULL;
if( ctx->owncloud_context->dav_session.ctx ) {
ne_forget_auth(ctx->owncloud_context->dav_session.ctx);
ne_session_destroy(ctx->owncloud_context->dav_session.ctx );
ctx->owncloud_context->dav_session.ctx = 0;
}
ctx->owncloud_context->is_first_propfind = true;
if( dav_session.ctx ) {
ne_forget_auth(dav_session.ctx);
ne_session_destroy( dav_session.ctx );
}
/* DEBUG_WEBDAV( "********** vio_module_shutdown" ); */
ctx->owncloud_context->dav_session.ctx = 0;
dav_session.ctx = 0;
// ne_sock_exit();
ctx->owncloud_context->_connected = 0; /* triggers dav_connect to go through the whole neon setup */
_connected = 0; /* triggers dav_connect to go through the whole neon setup */
SAFE_FREE( ctx->owncloud_context->dav_session.user );
SAFE_FREE( ctx->owncloud_context->dav_session.pwd );
SAFE_FREE( ctx->owncloud_context->dav_session.session_key);
SAFE_FREE( ctx->owncloud_context->dav_session.error_string );
SAFE_FREE( dav_session.user );
SAFE_FREE( dav_session.pwd );
SAFE_FREE( dav_session.session_key);
SAFE_FREE( dav_session.error_string );
return 0;
}
void owncloud_destroy(CSYNC* ctx)
{
owncloud_commit(ctx);
SAFE_FREE(ctx->owncloud_context);
ctx->owncloud_context = 0;
}
int owncloud_set_property(CSYNC* ctx, const char *key, void *data) {
int owncloud_set_property(const char *key, void *data) {
#define READ_STRING_PROPERTY(P) \
if (c_streq(key, #P)) { \
SAFE_FREE(ctx->owncloud_context->dav_session.P); \
ctx->owncloud_context->dav_session.P = c_strdup((const char*)data); \
SAFE_FREE(dav_session.P); \
dav_session.P = c_strdup((const char*)data); \
return 0; \
}
READ_STRING_PROPERTY(session_key)
@@ -797,43 +1027,48 @@ int owncloud_set_property(CSYNC* ctx, const char *key, void *data) {
#undef READ_STRING_PROPERTY
if (c_streq(key, "proxy_port")) {
ctx->owncloud_context->dav_session.proxy_port = *(int*)(data);
dav_session.proxy_port = *(int*)(data);
return 0;
}
if (c_streq(key, "read_timeout") || c_streq(key, "timeout")) {
ctx->owncloud_context->dav_session.read_timeout = *(int*)(data);
dav_session.read_timeout = *(int*)(data);
return 0;
}
if( c_streq(key, "csync_context")) {
dav_session.csync_ctx = data;
return 0;
}
if( c_streq(key, "get_dav_session")) {
/* Give the ne_session to the caller */
*(ne_session**)data = ctx->owncloud_context->dav_session.ctx;
*(ne_session**)data = dav_session.ctx;
return 0;
}
if( c_streq(key, "no_recursive_propfind")) {
ctx->owncloud_context->dav_session.no_recursive_propfind = *(bool*)(data);
dav_session.no_recursive_propfind = *(bool*)(data);
return 0;
}
if( c_streq(key, "redirect_callback")) {
if (data) {
csync_owncloud_redirect_callback_t* cb_wrapper = data;
ctx->owncloud_context->dav_session.redir_callback = *cb_wrapper;
dav_session.redir_callback = *cb_wrapper;
} else {
ctx->owncloud_context->dav_session.redir_callback = NULL;
dav_session.redir_callback = NULL;
}
}
return -1;
}
void owncloud_init(CSYNC* ctx) {
void owncloud_init(void *userdata) {
ctx->owncloud_context = c_malloc( sizeof( struct csync_owncloud_ctx_s ));
ctx->owncloud_context->csync_ctx = ctx; // back reference
ctx->owncloud_context->is_first_propfind = true;
_userdata = userdata;
_connected = 0; /* triggers dav_connect to go through the whole neon setup */
memset(&dav_session, 0, sizeof(dav_session));
/* Disable it, Mirall can enable it for the first sync (= no DB)*/
ctx->owncloud_context->dav_session.no_recursive_propfind = true;
dav_session.no_recursive_propfind = true;
}
/* vim: set ts=4 sw=4 et cindent: */
+150 -9
Ver Arquivo
@@ -21,18 +21,159 @@
#ifndef CSYNC_OWNCLOUD_H
#define CSYNC_OWNCLOUD_H
#include <errno.h>
#include <stdio.h>
#include <time.h>
#include <limits.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "config_csync.h"
#ifdef NEON_WITH_LFS /* Switch on LFS in libneon. Never remove the NE_LFS! */
#define NE_LFS
#endif
#include <neon/ne_basic.h>
#include <neon/ne_socket.h>
#include <neon/ne_session.h>
#include <neon/ne_request.h>
#include <neon/ne_props.h>
#include <neon/ne_auth.h>
#include <neon/ne_dates.h>
#include <neon/ne_compress.h>
#include <neon/ne_redirect.h>
#include "c_rbtree.h"
#include "c_lib.h"
#include "csync.h"
#include "csync_misc.h"
#include "csync_macros.h"
#include "c_private.h"
#include "httpbf.h"
#include "vio/csync_vio_file_stat.h"
#include "vio/csync_vio.h"
// Public API used by csync
csync_vio_handle_t *owncloud_opendir(CSYNC* ctx, const char *uri);
csync_vio_file_stat_t *owncloud_readdir(CSYNC* ctx, csync_vio_handle_t *dhandle);
int owncloud_closedir(CSYNC* ctx, csync_vio_handle_t *dhandle);
int owncloud_commit(CSYNC* ctx);
void owncloud_destroy(CSYNC* ctx);
char *owncloud_error_string(CSYNC* ctx);
void owncloud_init(CSYNC* ctx);
int owncloud_set_property(CSYNC* ctx, const char *key, void *data);
#include "csync_log.h"
#define DEBUG_WEBDAV(...) csync_log( 9, "oc_module", __VA_ARGS__);
enum resource_type {
resr_normal = 0,
resr_collection,
resr_reference,
resr_error
};
/* Struct to store data for each resource found during an opendir operation.
* It represents a single file entry.
*/
typedef struct resource {
char *uri; /* The complete uri */
char *name; /* The filename only */
enum resource_type type;
int64_t size;
time_t modtime;
char* md5;
char file_id[FILE_ID_BUF_SIZE+1];
struct resource *next;
} resource;
/* Struct to hold the context of a WebDAV PropFind operation to fetch
* a directory listing from the server.
*/
struct listdir_context {
struct resource *list; /* The list of result resources */
struct resource *currResource; /* A pointer to the current resource */
char *target; /* Request-URI of the PROPFIND */
unsigned int result_count; /* number of elements stored in list */
int ref; /* reference count, only destroy when it reaches 0 */
};
/* Our cache, key is a char* */
extern c_rbtree_t *propfind_recursive_cache;
/* Values are propfind_recursive_element: */
struct propfind_recursive_element {
struct resource *self;
struct resource *children;
struct propfind_recursive_element *parent;
};
typedef struct propfind_recursive_element propfind_recursive_element_t;
void clear_propfind_recursive_cache(void);
struct listdir_context *get_listdir_context_from_recursive_cache(const char *curi);
void fill_recursive_propfind_cache(const char *uri, const char *curi);
struct listdir_context *get_listdir_context_from_cache(const char *curi);
void fetch_resource_list_recursive(const char *uri, const char *curi);
typedef int (*csync_owncloud_redirect_callback_t)(CSYNC* ctx, const char* uri);
/* Struct with the WebDAV session */
struct dav_session_s {
ne_session *ctx;
char *user;
char *pwd;
char *proxy_type;
char *proxy_host;
int proxy_port;
char *proxy_user;
char *proxy_pwd;
char *session_key;
char *error_string;
int read_timeout;
CSYNC *csync_ctx;
bool no_recursive_propfind;
csync_owncloud_redirect_callback_t redir_callback;
};
extern struct dav_session_s dav_session;
/* The list of properties that is fetched in PropFind on a collection */
static const ne_propname ls_props[] = {
{ "DAV:", "getlastmodified" },
{ "DAV:", "getcontentlength" },
{ "DAV:", "resourcetype" },
{ "DAV:", "getetag"},
{ "http://owncloud.org/ns", "id"},
{ NULL, NULL }
};
void set_errno_from_http_errcode( int err );
void set_error_message( const char *msg );
void set_errno_from_neon_errcode( int neon_code );
int http_result_code_from_session(void);
void set_errno_from_session(void);
time_t oc_httpdate_parse( const char *date );
char *_cleanPath( const char* uri );
int _stat_perms( int type );
csync_vio_file_stat_t *resourceToFileStat( struct resource *res );
// Public API from vio
csync_vio_handle_t *owncloud_opendir(const char *uri);
csync_vio_file_stat_t *owncloud_readdir(csync_vio_handle_t *dhandle);
int owncloud_closedir(csync_vio_handle_t *dhandle);
int owncloud_stat(const char *uri, csync_vio_file_stat_t *buf);
int owncloud_commit(void);
char *owncloud_error_string(void);
void owncloud_init(void *userdata);
int owncloud_set_property(const char *key, void *data);
#endif /* CSYNC_OWNCLOUD_H */
-201
Ver Arquivo
@@ -1,201 +0,0 @@
/*
* libcsync -- a library to sync a directory with another
*
* Copyright (c) 2011 by Andreas Schneider <asn@cryptomilk.org>
* Copyright (c) 2012 by Klaas Freitag <freitag@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef CSYNC_OWNCLOUD_PRIVATE_H
#define CSYNC_OWNCLOUD_PRIVATE_H
#include <errno.h>
#include <stdio.h>
#include <time.h>
#include <limits.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "config_csync.h"
#ifdef NEON_WITH_LFS /* Switch on LFS in libneon. Never remove the NE_LFS! */
#define NE_LFS
#endif
#include <neon/ne_basic.h>
#include <neon/ne_socket.h>
#include <neon/ne_session.h>
#include <neon/ne_request.h>
#include <neon/ne_props.h>
#include <neon/ne_auth.h>
#include <neon/ne_dates.h>
#include <neon/ne_compress.h>
#include <neon/ne_redirect.h>
#include "c_rbtree.h"
#include "c_lib.h"
#include "csync.h"
#include "csync_misc.h"
#include "csync_macros.h"
#include "c_private.h"
#include "httpbf.h"
#include "vio/csync_vio_file_stat.h"
#include "vio/csync_vio.h"
#include "csync_log.h"
#include "csync_owncloud.h"
#define DEBUG_WEBDAV(...) csync_log( 9, "oc_module", __VA_ARGS__);
typedef int (*csync_owncloud_redirect_callback_t)(CSYNC* ctx, const char* uri);
/* Struct with the WebDAV session */
struct dav_session_s {
ne_session *ctx;
char *user;
char *pwd;
char *proxy_type;
char *proxy_host;
int proxy_port;
char *proxy_user;
char *proxy_pwd;
char *session_key;
char *error_string;
int read_timeout;
bool no_recursive_propfind;
csync_owncloud_redirect_callback_t redir_callback;
};
struct csync_owncloud_ctx_s {
CSYNC *csync_ctx;
// For the PROPFIND results
bool is_first_propfind;
struct listdir_context *propfind_cache;
c_rbtree_t *propfind_recursive_cache;
int propfind_recursive_cache_depth;
int propfind_recursive_cache_file_count;
int propfind_recursive_cache_folder_count;
// For the WebDAV connection
struct dav_session_s dav_session; /* The DAV Session, initialised in dav_connect */
int _connected; /* flag to indicate if a connection exists, ie.
the dav_session is valid */
};
typedef struct csync_owncloud_ctx_s csync_owncloud_ctx_t;
//typedef csync_owncloud_ctx_t* csync_owncloud_ctx_p;
enum resource_type {
resr_normal = 0,
resr_collection,
resr_reference,
resr_error
};
/* The list of properties that is fetched in PropFind on a collection */
static const ne_propname ls_props[] = {
{ "DAV:", "getlastmodified" },
{ "DAV:", "getcontentlength" },
{ "DAV:", "resourcetype" },
{ "DAV:", "getetag"},
{ "http://owncloud.org/ns", "id"},
{ "http://owncloud.org/ns", "dDU"},
{ "http://owncloud.org/ns", "dDC"},
{ "http://owncloud.org/ns", "permissions"},
{ NULL, NULL }
};
/* Struct to store data for each resource found during an opendir operation.
* It represents a single file entry.
*/
typedef struct resource {
char *uri; /* The complete uri */
char *name; /* The filename only */
enum resource_type type;
int64_t size;
time_t modtime;
char* md5;
char file_id[FILE_ID_BUF_SIZE+1];
// Those two are optional from the server. We can use those URL to download the file directly
// without going through the ownCloud instance.
char *directDownloadUrl;
char *directDownloadCookies;
// See https://github.com/owncloud/core/issues/8322
char remotePerm[REMOTE_PERM_BUF_SIZE+1];
struct resource *next;
} resource;
/* Struct to hold the context of a WebDAV PropFind operation to fetch
* a directory listing from the server.
*/
struct listdir_context {
struct resource *list; /* The list of result resources */
struct resource *currResource; /* A pointer to the current resource */
char *target; /* Request-URI of the PROPFIND */
unsigned int result_count; /* number of elements stored in list */
int ref; /* reference count, only destroy when it reaches 0 */
};
/* Values are propfind_recursive_element: */
struct propfind_recursive_element {
struct resource *self;
struct resource *children;
struct propfind_recursive_element *parent;
};
typedef struct propfind_recursive_element propfind_recursive_element_t;
void clear_propfind_recursive_cache(csync_owncloud_ctx_t *ctx);
struct listdir_context *get_listdir_context_from_recursive_cache(csync_owncloud_ctx_t *ctx, const char *curi);
void fill_recursive_propfind_cache(csync_owncloud_ctx_t *ctx, const char *uri, const char *curi);
struct listdir_context *get_listdir_context_from_cache(csync_owncloud_ctx_t *ctx, const char *curi);
void fetch_resource_list_recursive(csync_owncloud_ctx_t *ctx, const char *uri, const char *curi);
void set_errno_from_http_errcode( int err );
void set_error_message( csync_owncloud_ctx_t *ctx, const char *msg );
void set_errno_from_neon_errcode(csync_owncloud_ctx_t *ctx, int neon_code );
int http_result_code_from_session(csync_owncloud_ctx_t *ctx);
void set_errno_from_session(csync_owncloud_ctx_t *ctx);
time_t oc_httpdate_parse( const char *date );
char *_cleanPath( const char* uri );
void fill_webdav_properties_into_resource(struct resource* newres, const ne_prop_result_set *set);
void resourceToFileStat( csync_vio_file_stat_t *lfs, struct resource *res );
void resource_free(struct resource* o);
struct resource* resource_dup(struct resource* o);
void free_fetchCtx( struct listdir_context *ctx );
const char* csync_owncloud_get_platform(void);
#endif // CSYNC_OWNCLOUD_PRIVATE_H
+105 -39
Ver Arquivo
@@ -20,7 +20,42 @@
*/
#include "csync_owncloud.h"
#include "csync_owncloud_private.h"
c_rbtree_t *propfind_recursive_cache = NULL;
int propfind_recursive_cache_depth = 0;
int propfind_recursive_cache_file_count = 0;
int propfind_recursive_cache_folder_count = 0;
static struct resource* resource_dup(struct resource* o) {
struct resource *r = c_malloc (sizeof( struct resource ));
ZERO_STRUCTP(r);
r->uri = c_strdup(o->uri);
r->name = c_strdup(o->name);
r->type = o->type;
r->size = o->size;
r->modtime = o->modtime;
if( o->md5 ) {
r->md5 = c_strdup(o->md5);
}
r->next = o->next;
csync_vio_set_file_id(r->file_id, o->file_id);
return r;
}
static void resource_free(struct resource* o) {
struct resource* old = NULL;
while (o)
{
old = o;
o = o->next;
SAFE_FREE(old->uri);
SAFE_FREE(old->name);
SAFE_FREE(old->md5);
SAFE_FREE(old);
}
}
static void _tree_destructor(void *data) {
propfind_recursive_element_t *element = data;
@@ -29,27 +64,27 @@ static void _tree_destructor(void *data) {
SAFE_FREE(element);
}
void clear_propfind_recursive_cache(csync_owncloud_ctx_t *ctx)
void clear_propfind_recursive_cache(void)
{
if (ctx->propfind_recursive_cache) {
if (propfind_recursive_cache) {
DEBUG_WEBDAV("clear_propfind_recursive_cache Invalidating..");
c_rbtree_destroy(ctx->propfind_recursive_cache, _tree_destructor);
ctx->propfind_recursive_cache = NULL;
c_rbtree_destroy(propfind_recursive_cache, _tree_destructor);
propfind_recursive_cache = NULL;
}
}
struct listdir_context *get_listdir_context_from_recursive_cache(csync_owncloud_ctx_t *ctx, const char *curi)
struct listdir_context *get_listdir_context_from_recursive_cache(const char *curi)
{
propfind_recursive_element_t *element = NULL;
struct listdir_context *fetchCtx = NULL;
struct resource *iterator, *r;
if (!ctx->propfind_recursive_cache) {
if (!propfind_recursive_cache) {
DEBUG_WEBDAV("get_listdir_context_from_recursive_cache No cache");
return NULL;
}
element = c_rbtree_node_data(c_rbtree_find(ctx->propfind_recursive_cache, curi));
element = c_rbtree_node_data(c_rbtree_find(propfind_recursive_cache, curi));
if (!element) {
DEBUG_WEBDAV("get_listdir_context_from_recursive_cache No element %s in cache found", curi);
return NULL;
@@ -93,53 +128,83 @@ static int _data_cmp(const void *a, const void *b) {
const propfind_recursive_element_t *elementB = b;
return ne_path_compare(elementA->self->uri, elementB->self->uri);
}
static void propfind_results_recursive_callback(void *userdata,
static void propfind_results_recursive(void *userdata,
const ne_uri *uri,
const ne_prop_result_set *set)
{
struct resource *newres = 0;
const char *clength, *modtime, *file_id = NULL;
const char *resourcetype = NULL;
const char *md5sum = NULL;
const ne_status *status = NULL;
char *path = ne_path_unescape( uri->path );
char *parentPath;
char *propfindRootUri = (char*) userdata;
propfind_recursive_element_t *element = NULL;
propfind_recursive_element_t *pElement = NULL;
int depth = 0;
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
(void) status;
(void) propfindRootUri;
if (!ctx->propfind_recursive_cache) {
c_rbtree_create(&ctx->propfind_recursive_cache, _key_cmp, _data_cmp);
if (!propfind_recursive_cache) {
c_rbtree_create(&propfind_recursive_cache, _key_cmp, _data_cmp);
}
/* Fill the resource structure with the data about the file */
newres = c_malloc(sizeof(struct resource));
ZERO_STRUCTP(newres);
newres->uri = path; /* no need to strdup because ne_path_unescape already allocates */
newres->name = c_basename( path );
fill_webdav_properties_into_resource(newres, set);
if( newres->type == resr_collection) {
ctx->propfind_recursive_cache_folder_count++;
modtime = ne_propset_value( set, &ls_props[0] );
clength = ne_propset_value( set, &ls_props[1] );
resourcetype = ne_propset_value( set, &ls_props[2] );
md5sum = ne_propset_value( set, &ls_props[3] );
file_id = ne_propset_value( set, &ls_props[4] );
newres->type = resr_normal;
if( resourcetype && strncmp( resourcetype, "<DAV:collection>", 16 ) == 0) {
newres->type = resr_collection;
propfind_recursive_cache_folder_count++;
} else {
ctx->propfind_recursive_cache_file_count++;
/* DEBUG_WEBDAV("propfind_results_recursive %s [%d]", newres->uri, newres->type); */
propfind_recursive_cache_file_count++;
}
if (modtime) {
newres->modtime = oc_httpdate_parse(modtime);
}
/* DEBUG_WEBDAV("Parsing Modtime: %s -> %llu", modtime, (unsigned long long) newres->modtime ); */
newres->size = 0;
if (clength) {
newres->size = atoll(clength);
/* DEBUG_WEBDAV("Parsed File size for %s from %s: %lld", newres->name, clength, (long long)newres->size ); */
}
if( md5sum ) {
newres->md5 = csync_normalize_etag(md5sum);
}
csync_vio_set_file_id(newres->file_id, file_id);
/*
DEBUG_WEBDAV("propfind_results_recursive %s [%s] %s", newres->uri, newres->type == resr_collection ? "collection" : "file", newres->md5);
*/
/* Create new item in rb tree */
if (newres->type == resr_collection) {
DEBUG_WEBDAV("propfind_results_recursive %s is a folder", newres->uri);
/* Check if in rb tree */
element = c_rbtree_node_data(c_rbtree_find(ctx->propfind_recursive_cache,uri->path));
element = c_rbtree_node_data(c_rbtree_find(propfind_recursive_cache,uri->path));
/* If not, create a new item and insert it */
if (!element) {
element = c_malloc(sizeof(propfind_recursive_element_t));
element->self = resource_dup(newres);
element->self->next = 0;
element->children = NULL;
element->parent = NULL;
c_rbtree_insert(ctx->propfind_recursive_cache, element);
c_rbtree_insert(propfind_recursive_cache, element);
/* DEBUG_WEBDAV("results_recursive Added collection %s", newres->uri); */
}
}
@@ -149,7 +214,7 @@ static void propfind_results_recursive_callback(void *userdata,
if (parentPath) {
propfind_recursive_element_t *parentElement = NULL;
parentElement = c_rbtree_node_data(c_rbtree_find(ctx->propfind_recursive_cache,parentPath));
parentElement = c_rbtree_node_data(c_rbtree_find(propfind_recursive_cache,parentPath));
free(parentPath);
if (parentElement) {
@@ -165,9 +230,9 @@ static void propfind_results_recursive_callback(void *userdata,
depth++;
pElement = pElement->parent;
}
if (depth > ctx->propfind_recursive_cache_depth) {
if (depth > propfind_recursive_cache_depth) {
DEBUG_WEBDAV("propfind_results_recursive %s new maximum tree depth %d", newres->uri, depth);
ctx->propfind_recursive_cache_depth = depth;
propfind_recursive_cache_depth = depth;
}
/* DEBUG_WEBDAV("results_recursive Added child %s to collection %s", newres->uri, element->self->uri); */
@@ -179,7 +244,7 @@ static void propfind_results_recursive_callback(void *userdata,
newres = NULL;
}
void fetch_resource_list_recursive(csync_owncloud_ctx_t *ctx, const char *uri, const char *curi)
void fetch_resource_list_recursive(const char *uri, const char *curi)
{
int ret = 0;
ne_propfind_handler *hdl = NULL;
@@ -191,10 +256,10 @@ void fetch_resource_list_recursive(csync_owncloud_ctx_t *ctx, const char *uri, c
DEBUG_WEBDAV("fetch_resource_list_recursive Starting recursive propfind %s %s", uri, curi);
/* do a propfind request and parse the results in the results function, set as callback */
hdl = ne_propfind_create(ctx->dav_session.ctx, curi, depth);
hdl = ne_propfind_create(dav_session.ctx, curi, depth);
if(hdl) {
ret = ne_propfind_named(hdl, ls_props, propfind_results_recursive_callback, ctx);
ret = ne_propfind_named(hdl, ls_props, propfind_results_recursive, (void*)curi);
request = ne_propfind_get_request( hdl );
req_status = ne_get_status( request );
}
@@ -206,14 +271,14 @@ void fetch_resource_list_recursive(csync_owncloud_ctx_t *ctx, const char *uri, c
DEBUG_WEBDAV("ERROR: Request failed: status %d (%s)", req_status->code,
req_status->reason_phrase);
ret = NE_CONNECT;
set_error_message(ctx, req_status->reason_phrase);
set_error_message(req_status->reason_phrase);
}
DEBUG_WEBDAV("Recursive propfind result code %d.", req_status ? req_status->code : 0);
} else {
if( ret == NE_ERROR && req_status->code == 404) {
errno = ENOENT;
} else {
set_errno_from_neon_errcode(ctx, ret);
set_errno_from_neon_errcode(ret);
}
}
@@ -228,7 +293,7 @@ void fetch_resource_list_recursive(csync_owncloud_ctx_t *ctx, const char *uri, c
DEBUG_WEBDAV("ERROR: Content type of propfind request not XML: %s.",
content_type ? content_type: "<empty>");
errno = ERRNO_WRONG_CONTENT;
set_error_message(ctx, "Server error: PROPFIND reply is not XML formatted!");
set_error_message("Server error: PROPFIND reply is not XML formatted!");
ret = NE_CONNECT;
}
}
@@ -236,7 +301,7 @@ void fetch_resource_list_recursive(csync_owncloud_ctx_t *ctx, const char *uri, c
if( ret != NE_OK ) {
const char *err = NULL;
err = ne_get_error( ctx->dav_session.ctx );
err = ne_get_error( dav_session.ctx );
DEBUG_WEBDAV("WRN: propfind named failed with %d, request error: %s", ret, err ? err : "<nil>");
}
@@ -251,21 +316,22 @@ void fetch_resource_list_recursive(csync_owncloud_ctx_t *ctx, const char *uri, c
}
/* Called by owncloud_opendir()->fetch_resource_list() to fill the cache */
void fill_recursive_propfind_cache(csync_owncloud_ctx_t *ctx, const char *uri, const char *curi) {
fetch_resource_list_recursive(ctx, uri, curi);
extern struct listdir_context *propfind_cache;
void fill_recursive_propfind_cache(const char *uri, const char *curi) {
fetch_resource_list_recursive(uri, curi);
if (ctx->propfind_recursive_cache_depth <= 2) {
if (propfind_recursive_cache_depth <= 2) {
DEBUG_WEBDAV("fill_recursive_propfind_cache %s Server maybe did not give us an 'infinity' depth result", curi);
/* transform the cache to the normal cache in propfind_cache */
ctx->propfind_cache = get_listdir_context_from_recursive_cache(ctx, curi);
propfind_cache = get_listdir_context_from_recursive_cache(curi);
/* clear the cache, it is bogus since the server returned only results for Depth 1 */
clear_propfind_recursive_cache(ctx);
clear_propfind_recursive_cache();
} else {
DEBUG_WEBDAV("fill_recursive_propfind_cache %s We received %d elements deep for 'infinity' depth (%d folders, %d files)",
curi,
ctx->propfind_recursive_cache_depth,
ctx->propfind_recursive_cache_folder_count,
ctx->propfind_recursive_cache_file_count);
propfind_recursive_cache_depth,
propfind_recursive_cache_folder_count,
propfind_recursive_cache_file_count);
}
}
+39 -179
Ver Arquivo
@@ -20,15 +20,13 @@
*/
#include "csync_owncloud.h"
#include "csync_owncloud_private.h"
#include "csync_misc.h"
void set_error_message( csync_owncloud_ctx_t *ctx, const char *msg )
void set_error_message( const char *msg )
{
SAFE_FREE(ctx->dav_session.error_string);
SAFE_FREE(dav_session.error_string);
if( msg )
ctx->dav_session.error_string = c_strdup(msg);
dav_session.error_string = c_strdup(msg);
}
void set_errno_from_http_errcode( int err ) {
@@ -106,12 +104,12 @@ void set_errno_from_http_errcode( int err ) {
errno = new_errno;
}
int http_result_code_from_session(csync_owncloud_ctx_t *ctx) {
const char *p = ne_get_error( ctx->dav_session.ctx );
int http_result_code_from_session() {
const char *p = ne_get_error( dav_session.ctx );
char *q;
int err;
set_error_message(ctx, p); /* remember the error message */
set_error_message(p); /* remember the error message */
err = strtol(p, &q, 10);
if (p == q) {
@@ -120,8 +118,8 @@ int http_result_code_from_session(csync_owncloud_ctx_t *ctx) {
return err;
}
void set_errno_from_session(csync_owncloud_ctx_t *ctx) {
int err = http_result_code_from_session(ctx);
void set_errno_from_session() {
int err = http_result_code_from_session();
if( err == EIO || err == ERRNO_ERROR_STRING) {
errno = err;
@@ -130,7 +128,7 @@ void set_errno_from_session(csync_owncloud_ctx_t *ctx) {
}
}
void set_errno_from_neon_errcode(csync_owncloud_ctx_t *ctx, int neon_code ) {
void set_errno_from_neon_errcode( int neon_code ) {
if( neon_code != NE_OK ) {
DEBUG_WEBDAV("Neon error code was %d", neon_code);
@@ -139,7 +137,7 @@ void set_errno_from_neon_errcode(csync_owncloud_ctx_t *ctx, int neon_code ) {
switch(neon_code) {
case NE_OK: /* Success, but still the possiblity of problems */
case NE_ERROR: /* Generic error; use ne_get_error(session) for message */
set_errno_from_session(ctx); /* Something wrong with http communication */
set_errno_from_session(); /* Something wrong with http communication */
break;
case NE_LOOKUP: /* Server or proxy hostname lookup failed */
errno = ERRNO_LOOKUP_ERROR;
@@ -281,9 +279,19 @@ time_t oc_httpdate_parse( const char *date ) {
/*
* helper: convert a resource struct to file_stat struct.
*/
void resourceToFileStat(csync_vio_file_stat_t *lfs, struct resource *res )
csync_vio_file_stat_t *resourceToFileStat( struct resource *res )
{
ZERO_STRUCTP(lfs);
csync_vio_file_stat_t *lfs = NULL;
if( ! res ) {
return NULL;
}
lfs = c_malloc(sizeof(csync_vio_file_stat_t));
if (lfs == NULL) {
errno = ENOMEM;
return NULL;
}
lfs->name = c_strdup( res->name );
@@ -304,178 +312,30 @@ void resourceToFileStat(csync_vio_file_stat_t *lfs, struct resource *res )
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
if( res->md5 ) {
lfs->etag = c_strdup(res->md5);
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ETAG;
}
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ETAG;
csync_vio_file_stat_set_file_id(lfs, res->file_id);
if (res->directDownloadUrl) {
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADURL;
lfs->directDownloadUrl = c_strdup(res->directDownloadUrl);
}
if (res->directDownloadCookies) {
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADCOOKIES;
lfs->directDownloadCookies = c_strdup(res->directDownloadCookies);
}
if (strlen(res->remotePerm) > 0) {
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERM;
strncpy(lfs->remotePerm, res->remotePerm, sizeof(lfs->remotePerm));
}
return lfs;
}
void fill_webdav_properties_into_resource(struct resource* newres, const ne_prop_result_set *set)
{
const char *clength, *modtime, *file_id = NULL;
const char *directDownloadUrl = NULL;
const char *directDownloadCookies = NULL;
const char *resourcetype = NULL;
const char *etag = NULL;
const char *perm = NULL;
/* WebDAV does not deliver permissions. Set a default here. */
int _stat_perms( int type ) {
int ret = 0;
modtime = ne_propset_value( set, &ls_props[0] );
clength = ne_propset_value( set, &ls_props[1] );
resourcetype = ne_propset_value( set, &ls_props[2] );
etag = ne_propset_value( set, &ls_props[3] );
file_id = ne_propset_value( set, &ls_props[4] );
directDownloadUrl = ne_propset_value( set, &ls_props[5] );
directDownloadCookies = ne_propset_value( set, &ls_props[6] );
perm = ne_propset_value( set, &ls_props[7] );
if( resourcetype && strncmp( resourcetype, "<DAV:collection>", 16 ) == 0) {
newres->type = resr_collection;
if( type == CSYNC_VIO_FILE_TYPE_DIRECTORY ) {
/* DEBUG_WEBDAV("Setting mode in stat (dir)"); */
/* directory permissions */
ret = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR /* directory, rwx for user */
| S_IRGRP | S_IXGRP /* rx for group */
| S_IROTH | S_IXOTH; /* rx for others */
} else {
newres->type = resr_normal;
}
if (modtime) {
newres->modtime = oc_httpdate_parse(modtime);
}
/* DEBUG_WEBDAV("Parsing Modtime: %s -> %llu", modtime, (unsigned long long) newres->modtime ); */
newres->size = 0;
if (clength) {
newres->size = atoll(clength);
/* DEBUG_WEBDAV("Parsed File size for %s from %s: %lld", newres->name, clength, (long long)newres->size ); */
}
if( etag ) {
newres->md5 = csync_normalize_etag(etag);
}
csync_vio_set_file_id(newres->file_id, file_id);
/*
DEBUG_WEBDAV("propfind_results_recursive %s [%s] %s", newres->uri, newres->type == resr_collection ? "collection" : "file", newres->md5);
*/
if (directDownloadUrl) {
newres->directDownloadUrl = c_strdup(directDownloadUrl);
}
if (directDownloadCookies) {
newres->directDownloadCookies = c_strdup(directDownloadCookies);
}
/* DEBUG_WEBDAV("fill_webdav_properties_into_resource %s >%p< ", newres->name, perm ); */
if (perm && !perm[0]) {
// special meaning for our code: server returned permissions but are empty
// meaning only reading is allowed for this resource
newres->remotePerm[0] = ' ';
// see _csync_detect_update()
} else if (perm && strlen(perm) < sizeof(newres->remotePerm)) {
strncpy(newres->remotePerm, perm, sizeof(newres->remotePerm));
} else {
// old server, keep newres->remotePerm empty
/* regualar file permissions */
/* DEBUG_WEBDAV("Setting mode in stat (file)"); */
ret = S_IFREG | S_IRUSR | S_IWUSR /* regular file, user read & write */
| S_IRGRP /* group read perm */
| S_IROTH; /* others read perm */
}
return ret;
}
struct resource* resource_dup(struct resource* o) {
struct resource *r = c_malloc (sizeof( struct resource ));
ZERO_STRUCTP(r);
r->uri = c_strdup(o->uri);
r->name = c_strdup(o->name);
r->type = o->type;
r->size = o->size;
r->modtime = o->modtime;
if( o->md5 ) {
r->md5 = c_strdup(o->md5);
}
if (o->directDownloadUrl) {
r->directDownloadUrl = c_strdup(o->directDownloadUrl);
}
if (o->directDownloadCookies) {
r->directDownloadCookies = c_strdup(o->directDownloadCookies);
}
if (o->remotePerm) {
strncpy(r->remotePerm, o->remotePerm, sizeof(r->remotePerm));
}
r->next = o->next;
csync_vio_set_file_id(r->file_id, o->file_id);
return r;
}
void resource_free(struct resource* o) {
struct resource* old = NULL;
while (o)
{
old = o;
o = o->next;
SAFE_FREE(old->uri);
SAFE_FREE(old->name);
SAFE_FREE(old->md5);
SAFE_FREE(old->directDownloadUrl);
SAFE_FREE(old->directDownloadCookies);
SAFE_FREE(old);
}
}
void free_fetchCtx( struct listdir_context *ctx )
{
struct resource *newres, *res;
if( ! ctx ) return;
newres = ctx->list;
res = newres;
ctx->ref--;
if (ctx->ref > 0) return;
SAFE_FREE(ctx->target);
while( res ) {
SAFE_FREE(res->uri);
SAFE_FREE(res->name);
SAFE_FREE(res->md5);
memset( res->file_id, 0, FILE_ID_BUF_SIZE+1 );
SAFE_FREE(res->directDownloadUrl);
SAFE_FREE(res->directDownloadCookies);
newres = res->next;
SAFE_FREE(res);
res = newres;
}
SAFE_FREE(ctx);
}
// as per http://sourceforge.net/p/predef/wiki/OperatingSystems/
// extend as required
const char* csync_owncloud_get_platform() {
#if defined (_WIN32)
return "Windows";
#elif defined(__APPLE__)
return "Macintosh";
#elif defined(__gnu_linux__)
return "Linux";
#elif defined(__DragonFly__)
/* might also define __FreeBSD__ */
return "DragonFlyBSD";
#elif defined(__FreeBSD__)
return "FreeBSD";
#elif defined(__NetBSD__)
return "NetBSD";
#elif defined(__OpenBSD__)
return "OpenBSD";
#elif defined(sun) || defined(__sun)
return "Solaris";
#else
return "Unknown OS";
#endif
}
+26 -12
Ver Arquivo
@@ -61,6 +61,18 @@
*/
#define MAX_DEPTH 50
/**
* Maximum time difference between two replicas in seconds
*/
#define MAX_TIME_DIFFERENCE 10
/**
* Maximum size of a buffer for transfer
*/
#ifndef MAX_XFER_BUF_SIZE
#define MAX_XFER_BUF_SIZE (16 * 1024)
#endif
#define CSYNC_STATUS_INIT 1 << 0
#define CSYNC_STATUS_UPDATE 1 << 1
#define CSYNC_STATUS_RECONCILE 1 << 2
@@ -78,8 +90,6 @@ enum csync_replica_e {
typedef struct csync_file_stat_s csync_file_stat_t;
struct csync_owncloud_ctx_s; // csync_owncloud.c
/**
* @brief csync public structure
*/
@@ -94,6 +104,7 @@ struct csync_s {
char *file;
sqlite3 *db;
int exists;
int disabled;
sqlite3_stmt* by_hash_stmt;
sqlite3_stmt* by_fileid_stmt;
@@ -115,15 +126,22 @@ struct csync_s {
enum csync_replica_e type;
int read_from_db;
c_list_t *ignored_cleanup;
const char *root_perms; /* Permission of the root folder. (Since the root folder is not in the db tree, we need to keep a separate entry.) */
} remote;
#if defined(HAVE_ICONV) && defined(WITH_ICONV)
struct {
int sync_symbolic_links;
char *config_dir;
bool local_only_mode;
int timeout;
#if defined(HAVE_ICONV) && defined(WITH_ICONV)
iconv_t iconv_cd;
} options;
#endif
} options;
struct {
uid_t uid;
uid_t euid;
} pwd;
/* replica we are currently walking */
enum csync_replica_e current;
@@ -144,8 +162,6 @@ struct csync_s {
volatile int abort;
void *rename_info;
int read_from_db_disabled;
struct csync_owncloud_ctx_s *owncloud_context;
};
@@ -158,6 +174,8 @@ struct csync_file_stat_s {
int64_t size; /* u64 */
size_t pathlen; /* u64 */
uint64_t inode; /* u64 */
uid_t uid; /* u32 */
gid_t gid; /* u32 */
mode_t mode; /* u32 */
int nlink; /* u32 */
int type; /* u32 */
@@ -167,10 +185,6 @@ struct csync_file_stat_s {
char *destpath; /* for renames */
const char *etag;
char file_id[FILE_ID_BUF_SIZE+1]; /* the ownCloud file id is fixed width of 21 byte. */
char *directDownloadUrl;
char *directDownloadCookies;
char remotePerm[REMOTE_PERM_BUF_SIZE+1];
CSYNC_STATUS error_status;
enum csync_instructions_e instruction; /* u32 */
-2
Ver Arquivo
@@ -184,7 +184,6 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
csync_vio_set_file_id( other->file_id, cur->file_id );
}
other->inode = cur->inode;
other->should_update_etag = true;
cur->instruction = CSYNC_INSTRUCTION_NONE;
} else if (other->instruction == CSYNC_INSTRUCTION_REMOVE) {
other->instruction = CSYNC_INSTRUCTION_RENAME;
@@ -194,7 +193,6 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
csync_vio_set_file_id( other->file_id, cur->file_id );
}
other->inode = cur->inode;
other->should_update_etag = true;
cur->instruction = CSYNC_INSTRUCTION_NONE;
} else if (other->instruction == CSYNC_INSTRUCTION_NEW) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "OOOO=> NEW detected in other tree!");
+26 -7
Ver Arquivo
@@ -58,6 +58,28 @@ int csync_get_statedb_exists(CSYNC *ctx) {
return ctx->statedb.exists;
}
/* Set the hide attribute in win32. That makes it invisible in normal explorers */
static void _csync_win32_hide_file( const char *file ) {
#ifdef _WIN32
mbchar_t *fileName;
DWORD dwAttrs;
if( !file ) return;
fileName = c_utf8_to_locale( file );
dwAttrs = GetFileAttributesW(fileName);
if (dwAttrs != INVALID_FILE_ATTRIBUTES) {
if (!(dwAttrs & FILE_ATTRIBUTE_HIDDEN)) {
SetFileAttributesW(fileName, dwAttrs | FILE_ATTRIBUTE_HIDDEN );
}
}
c_free_locale_string(fileName);
#else
(void) file;
#endif
}
static int _csync_check_db_integrity(sqlite3 *db) {
c_strlist_t *result = NULL;
int rc = -1;
@@ -146,7 +168,7 @@ static int _csync_statedb_check(const char *statedb) {
rc = sqlite3_open(statedb, &db);
if (rc == SQLITE_OK) {
sqlite3_close(db);
csync_win32_set_file_hidden(statedb, true);
_csync_win32_hide_file(statedb);
return 1;
}
sqlite3_close(db);
@@ -300,6 +322,8 @@ static int _csync_file_stat_from_metadata_table( csync_file_stat_t **st, sqlite3
name = (const char*) sqlite3_column_text(stmt, 2);
memcpy((*st)->path, (len ? name : ""), len + 1);
(*st)->inode = sqlite3_column_int64(stmt,3);
(*st)->uid = sqlite3_column_int(stmt, 4);
(*st)->gid = sqlite3_column_int(stmt, 5);
(*st)->mode = sqlite3_column_int(stmt, 6);
(*st)->modtime = strtoul((char*)sqlite3_column_text(stmt, 7), NULL, 10);
@@ -313,11 +337,6 @@ static int _csync_file_stat_from_metadata_table( csync_file_stat_t **st, sqlite3
if(column_count > 10 && sqlite3_column_text(stmt,10)) {
csync_vio_set_file_id((*st)->file_id, (char*) sqlite3_column_text(stmt, 10));
}
if(column_count > 11 && sqlite3_column_text(stmt,11)) {
strncpy((*st)->remotePerm,
(char*) sqlite3_column_text(stmt, 11),
REMOTE_PERM_BUF_SIZE);
}
}
}
return rc;
@@ -457,7 +476,7 @@ char *csync_statedb_get_etag( CSYNC *ctx, uint64_t jHash ) {
return ret;
}
#define BELOW_PATH_QUERY "SELECT phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm FROM metadata WHERE path LIKE(?)"
#define BELOW_PATH_QUERY "SELECT phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid FROM metadata WHERE path LIKE(?)"
int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
int rc;
+15 -41
Ver Arquivo
@@ -140,14 +140,6 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
len = strlen(path);
/* This code should probably be in csync_exclude, but it does not have the fs parameter.
Keep it here for now and TODO also find out if we want this for Windows
https://github.com/owncloud/mirall/issues/2086 */
if (fs->flags & CSYNC_VIO_FILE_FLAGS_HIDDEN) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file excluded because it is a hidden file: %s", path);
return 0;
}
/* Check if file is excluded */
excluded = csync_excluded(ctx, path,type);
@@ -262,22 +254,20 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
st->instruction = CSYNC_INSTRUCTION_EVAL;
goto out;
}
bool metadata_differ = (ctx->current == REMOTE_REPLICA && (!c_streq(fs->file_id, tmp->file_id)
|| !c_streq(fs->remotePerm, tmp->remotePerm)))
|| (ctx->current == LOCAL_REPLICA && fs->inode != tmp->inode);
if (type == CSYNC_FTW_TYPE_DIR && ctx->current == REMOTE_REPLICA
&& !metadata_differ && !ctx->read_from_db_disabled) {
&& c_streq(fs->file_id, tmp->file_id) && !ctx->read_from_db_disabled) {
/* If both etag and file id are equal for a directory, read all contents from
* the database.
* The metadata comparison ensure that we fetch all the file id or permission when
* upgrading owncloud
* The comparison of file id ensure that we fetch all the file id when upgrading from
* owncloud 5 to owncloud 6.
*/
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Reading from database: %s", path);
ctx->remote.read_from_db = true;
}
if (metadata_differ) {
/* file id or permissions has changed. Which means we need to update them in the DB. */
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Need to update metadata for: %s", path);
if (!c_streq(fs->file_id, tmp->file_id) && ctx->current == REMOTE_REPLICA) {
/* file id has changed. Which means we need to update the DB.
* (upgrade from owncloud 5 to owncloud 6 for instence) */
st->should_update_etag = true;
}
st->instruction = CSYNC_INSTRUCTION_NONE;
@@ -374,6 +364,8 @@ out:
st->mode = fs->mode;
st->size = fs->size;
st->modtime = fs->mtime;
st->uid = fs->uid;
st->gid = fs->gid;
st->nlink = fs->nlink;
st->type = type;
st->etag = NULL;
@@ -382,17 +374,6 @@ out:
st->etag = c_strdup(fs->etag);
}
csync_vio_set_file_id(st->file_id, fs->file_id);
if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADURL) {
SAFE_FREE(st->directDownloadUrl);
st->directDownloadUrl = c_strdup(fs->directDownloadUrl);
}
if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADCOOKIES) {
SAFE_FREE(st->directDownloadCookies);
st->directDownloadCookies = c_strdup(fs->directDownloadCookies);
}
if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_PERM) {
strncpy(st->remotePerm, fs->remotePerm, REMOTE_PERM_BUF_SIZE);
}
fastout: /* target if the file information is read from database into st */
st->phash = h;
@@ -608,14 +589,9 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
continue;
}
/* Only for the local replica we have to stat(), for the remote one we have all data already */
if (ctx->replica == LOCAL_REPLICA) {
fs = csync_vio_file_stat_new();
res = csync_vio_stat(ctx, filename, fs);
} else {
fs = dirent;
res = 0;
}
/* == see if really stat has to be called. */
fs = csync_vio_file_stat_new();
res = csync_vio_stat(ctx, filename, fs);
if( res == 0) {
switch (fs->type) {
@@ -670,10 +646,7 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
previous_fs->child_modified = ctx->current_fs->child_modified;
}
/* Only for the local replica we have to destroy stat(), for the remote one it is a pointer to dirent */
if (ctx->replica == LOCAL_REPLICA) {
csync_vio_file_stat_destroy(fs);
}
csync_vio_file_stat_destroy(fs);
if (rc < 0) {
if (CSYNC_STATUS_IS_OK(ctx->status_code)) {
@@ -701,7 +674,8 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
if (flag == CSYNC_FTW_FLAG_DIR && ctx->current_fs
&& (ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL ||
ctx->current_fs->instruction == CSYNC_INSTRUCTION_NEW)) {
ctx->current_fs->instruction == CSYNC_INSTRUCTION_NEW ||
ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL_RENAME)) {
ctx->current_fs->should_update_etag = true;
}
+53
Ver Arquivo
@@ -128,6 +128,59 @@ void csync_win32_set_file_hidden( const char *file, bool h ) {
#endif
}
csync_vio_file_stat_t *csync_vio_convert_file_stat(csync_file_stat_t *st) {
csync_vio_file_stat_t *vfs = NULL;
if (st == NULL) {
return NULL;
}
vfs = csync_vio_file_stat_new();
if (vfs == NULL) {
return NULL;
}
vfs->acl = NULL;
if (st->pathlen > 0) {
vfs->name = c_strdup(st->path);
}
vfs->uid = st->uid;
vfs->gid = st->gid;
vfs->atime = 0;
vfs->mtime = st->modtime;
vfs->ctime = 0;
vfs->size = st->size;
vfs->blksize = 0; /* Depricated. */
vfs->blkcount = 0;
vfs->mode = st->mode;
vfs->device = 0;
vfs->inode = st->inode;
vfs->nlink = st->nlink;
/* fields. */
vfs->fields = CSYNC_VIO_FILE_STAT_FIELDS_TYPE
+ CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS
+ CSYNC_VIO_FILE_STAT_FIELDS_INODE
+ CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT
+ CSYNC_VIO_FILE_STAT_FIELDS_SIZE
+ CSYNC_VIO_FILE_STAT_FIELDS_MTIME
+ CSYNC_VIO_FILE_STAT_FIELDS_UID
+ CSYNC_VIO_FILE_STAT_FIELDS_GID;
if (st->type == CSYNC_FTW_TYPE_DIR)
vfs->type = CSYNC_VIO_FILE_TYPE_DIRECTORY;
else if (st->type == CSYNC_FTW_TYPE_FILE)
vfs->type = CSYNC_VIO_FILE_TYPE_REGULAR;
else if (st->type == CSYNC_FTW_TYPE_SLINK)
vfs->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK;
else
vfs->type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
return vfs;
}
bool (*csync_file_locked_or_open_ext) (const char*) = 0; // filled in by library user
void set_csync_file_locked_or_open_ext(bool (*f) (const char*));
void set_csync_file_locked_or_open_ext(bool (*f) (const char*)) {
+3
Ver Arquivo
@@ -32,5 +32,8 @@ void csync_memstat_check(void);
void csync_win32_set_file_hidden( const char *file, bool hidden );
/* Convert a csync_file_stat_t to csync_vio_file_stat_t */
csync_vio_file_stat_t *csync_vio_convert_file_stat(csync_file_stat_t *st);
bool csync_file_locked_or_open( const char *dir, const char *fname);
#endif /* _CSYNC_UTIL_H */
+2
Ver Arquivo
@@ -20,6 +20,8 @@ set(CSTDLIB_LINK_LIBRARIES
set(cstdlib_SRCS
c_alloc.c
c_dir.c
c_file.c
c_list.c
c_path.c
c_rbtree.c
+189
Ver Arquivo
@@ -0,0 +1,189 @@
/*
* cynapses libc functions
*
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "c_private.h"
#include "c_macro.h"
#include "c_alloc.h"
#include "c_dir.h"
#include "c_string.h"
int c_mkdirs(const char *path, mode_t mode) {
int tmp;
csync_stat_t sb;
mbchar_t *wpath = c_utf8_to_locale(path);
mbchar_t *swpath = NULL;
if (path == NULL) {
errno = EINVAL;
return -1;
}
if (_tstat(wpath, &sb) == 0) {
if (! S_ISDIR(sb.st_mode)) {
errno = ENOTDIR;
c_free_locale_string(wpath);
return -1;
}
}
tmp = strlen(path);
while(tmp > 0 && path[tmp - 1] == '/') --tmp;
while(tmp > 0 && path[tmp - 1] != '/') --tmp;
while(tmp > 0 && path[tmp - 1] == '/') --tmp;
if (tmp > 0) {
char subpath[tmp + 1];
memcpy(subpath, path, tmp);
subpath[tmp] = '\0';
swpath = c_utf8_to_locale(subpath);
if (_tstat(swpath, &sb) == 0) {
if (! S_ISDIR(sb.st_mode)) {
c_free_locale_string(swpath);
c_free_locale_string(wpath);
errno = ENOTDIR;
return -1;
}
} else if (errno != ENOENT) {
c_free_locale_string(wpath);
c_free_locale_string(swpath);
return -1;
} else if (c_mkdirs(subpath, mode) < 0) {
c_free_locale_string(swpath);
c_free_locale_string(wpath);
return -1;
}
}
tmp = _tmkdir(wpath, mode);
c_free_locale_string(swpath);
c_free_locale_string(wpath);
if ((tmp < 0) && (errno == EEXIST)) {
return 0;
}
return tmp;
}
int c_rmdirs(const char *path) {
_TDIR *d;
struct _tdirent *dp;
csync_stat_t sb;
char *fname = NULL;
mbchar_t *wfname = NULL;
mbchar_t *wpath = c_utf8_to_locale(path);
char *rd_name = NULL;
if ((d = _topendir(wpath)) != NULL) {
while( _tstat(wpath, &sb) == 0) {
/* if we can remove the directory we're done */
if (_trmdir(wpath) == 0) {
break;
}
switch (errno) {
case ENOTEMPTY:
case EEXIST:
case EBADF:
break; /* continue */
default:
_tclosedir(d);
c_free_locale_string(wpath);
return 0;
}
while ((dp = _treaddir(d)) != NULL) {
size_t len;
rd_name = c_utf8_from_locale(dp->d_name);
/* skip '.' and '..' */
if( c_streq( rd_name, "." ) || c_streq( rd_name, ".." ) ) {
c_free_locale_string(rd_name);
continue;
}
len = strlen(path) + strlen(rd_name) + 2;
fname = c_malloc(len);
if (fname == NULL) {
_tclosedir(d);
c_free_locale_string(rd_name);
c_free_locale_string(wpath);
return -1;
}
snprintf(fname, len, "%s/%s", path, rd_name);
wfname = c_utf8_to_locale(fname);
/* stat the file */
if (_tstat(wfname, &sb) != -1) {
#ifdef __unix__
if (S_ISDIR(sb.st_mode) && !S_ISLNK(sb.st_mode)) {
#else
if (S_ISDIR(sb.st_mode)) {
#endif
if (_trmdir(wfname) < 0) { /* can't be deleted */
if (errno == EACCES) {
_tclosedir(d);
SAFE_FREE(fname);
c_free_locale_string(wfname);
c_free_locale_string(rd_name);
c_free_locale_string(wpath);
return -1;
}
c_rmdirs(fname);
}
} else {
_tunlink(wfname);
}
} /* lstat */
SAFE_FREE(fname);
c_free_locale_string(wfname);
c_free_locale_string(rd_name);
} /* readdir */
_trewinddir(d);
}
} else {
c_free_locale_string(wpath);
return -1;
}
c_free_locale_string(wpath);
_tclosedir(d);
return 0;
}
int c_isdir(const char *path) {
csync_stat_t sb;
mbchar_t *wpath = c_utf8_to_locale(path);
int re = 0;
if (path != NULL) {
if (_tstat (wpath, &sb) == 0 && S_ISDIR(sb.st_mode)) {
re = 1;
}
}
c_free_locale_string(wpath);
return re;
}
+86
Ver Arquivo
@@ -0,0 +1,86 @@
/*
* cynapses libc functions
*
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file c_dir.h
*
* @brief Interface of the cynapses libc directory function
*
* @defgroup cynDirInternals cynapses libc directory functions
* @ingroup cynLibraryAPI
*
* @{
*/
#ifndef _C_DIR_H
#define _C_DIR_H
#include <sys/types.h>
/**
* @brief Create parent directories as needed.
*
* The newly created directory will be owned by the effective user ID of the
* process.
*
* @param path The path to the directory to create.
*
* @param mode Specifies the permissions to use. It is modified
* by the process's umask in the usual way: the
* permissions of the created file are (mode & ~umask).
*
* @return 0 on success, < 0 on error with errno set:
* - EACCES The parent directory does not allow write
* permission to the process, or one of the directories
* - ENOTDIR if durl is not a directory
* - EINVAL NULL durl passed or smbc_init not called.
* - ENOMEM Insufficient memory was available.
*
* @see mkdir()
*/
int c_mkdirs(const char *path, mode_t mode);
/**
* @brief Remove the directory and subdirectories including the content.
*
* This removes all directories and files recursivly.
*
* @param dir The directory to remove recusively.
*
* @return 0 on success, < 0 on error with errno set.
*/
int c_rmdirs(const char *dir);
/**
* @brief Check if a path is a directory.
*
* @param path The path to check.
*
* @return 1 if the path is a directory, 0 if the path doesn't exist, is a
* file or can't be accessed.
*/
int c_isdir(const char *path);
/**
* }@
*/
#endif /* _CDIR_H */
+346
Ver Arquivo
@@ -0,0 +1,346 @@
/*
* cynapses libc functions
*
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
* Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifdef _WIN32
#include <windef.h>
#include <winbase.h>
#endif
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include "c_file.h"
#include "c_string.h"
#include "c_private.h"
#ifdef _WIN32
/* check if path is a symlink */
int c_islink(const char *path) {
int re = 0;
mbchar_t *wpath = 0;
DWORD dwAttrs;
WIN32_FIND_DATAW FindFileData;
HANDLE hFind;
wpath = c_utf8_to_locale(path);
dwAttrs = GetFileAttributesW(wpath);
if (dwAttrs != INVALID_FILE_ATTRIBUTES) {
if ((dwAttrs & FILE_ATTRIBUTE_REPARSE_POINT)) {
hFind = FindFirstFileW(wpath, &FindFileData );
if (hFind != INVALID_HANDLE_VALUE) {
if( (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
(FindFileData.dwReserved0 & IO_REPARSE_TAG_SYMLINK) ) {
re = 1;
}
}
FindClose(hFind);
}
}
c_free_locale_string(wpath);
return re;
}
#endif
/* check if path is a file */
int c_isfile(const char *path) {
csync_stat_t sb;
mbchar_t *wpath = c_utf8_to_locale(path);
int re = _tstat(wpath, &sb);
c_free_locale_string(wpath);
if (re< 0) {
return 0;
}
#ifdef __unix__
if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode)) {
#else
if (S_ISREG(sb.st_mode)) {
#endif
return 1;
}
return 0;
}
/* copy file from src to dst, overwrites dst */
#ifdef _WIN32
int c_copy(const char* src, const char *dst, mode_t mode) {
int rc = -1;
mbchar_t *wsrc = 0;
mbchar_t *wdst = 0;
(void) mode; /* unused on win32 */
if(src && dst) {
wsrc = c_utf8_to_locale(src);
wdst = c_utf8_to_locale(dst);
if (CopyFileW(wsrc, wdst, FALSE)) {
rc = 0;
}
c_free_locale_string(wsrc);
c_free_locale_string(wdst);
if( rc < 0 ) {
errno = GetLastError();
}
}
return rc;
}
#else
int c_copy(const char* src, const char *dst, mode_t mode) {
int srcfd = -1;
int dstfd = -1;
int rc = -1;
ssize_t bread, bwritten;
csync_stat_t sb;
char buf[4096];
if (c_streq(src, dst)) {
return -1;
}
srcfd = open(src, O_RDONLY, 0);
if (srcfd < 0) {
goto out;
}
rc = _tfstat(srcfd, &sb);
if (rc < 0) {
goto out;
}
if (S_ISDIR(sb.st_mode)) {
errno = EISDIR;
rc = -1;
goto out;
}
if (mode == 0) {
mode = sb.st_mode;
}
dstfd = open(dst, O_CREAT|O_WRONLY|O_TRUNC, mode);
if (dstfd < 0) {
rc = -1;
goto out;
}
rc = _tfstat(dstfd, &sb);
if (rc == 0) {
if (S_ISDIR(sb.st_mode)) {
errno = EISDIR;
rc = -1;
goto out;
}
}
for (;;) {
bread = read(srcfd, buf, sizeof(buf));
if (bread == 0) {
/* done */
break;
} else if (bread < 0) {
errno = ENODATA;
rc = -1;
goto out;
}
bwritten = write(dstfd, buf, bread);
if (bwritten < 0) {
errno = ENODATA;
rc = -1;
goto out;
}
if (bread != bwritten) {
errno = EFAULT;
rc = -1;
goto out;
}
}
#ifdef __unix__
fsync(dstfd);
#endif
rc = 0;
out:
if (srcfd >= 0) {
close(srcfd);
}
if (dstfd >= 0) {
close(dstfd);
}
if (rc < 0 && c_isfile(dst)) {
unlink(dst);
}
return rc;
}
#endif
int c_rename( const char *src, const char *dst ) {
mbchar_t *nuri = NULL;
mbchar_t *ouri = NULL;
int rc = 0;
nuri = c_utf8_to_locale(dst);
if (nuri == NULL) {
return -1;
}
ouri = c_utf8_to_locale(src);
if (ouri == NULL) {
c_free_locale_string(nuri);
return -1;
}
#ifdef _WIN32
{
#define MAX_TRIES_RENAME 3
int err = 0;
int cnt = 0;
do {
BOOL ok;
ok = MoveFileExW(ouri,
nuri,
MOVEFILE_COPY_ALLOWED +
MOVEFILE_REPLACE_EXISTING +
MOVEFILE_WRITE_THROUGH);
if (!ok) {
/* error */
err = GetLastError();
if( (err == ERROR_ACCESS_DENIED ||
err == ERROR_LOCK_VIOLATION ||
err == ERROR_SHARING_VIOLATION) && cnt < MAX_TRIES_RENAME ) {
cnt++;
Sleep(cnt*100);
continue;
}
}
break;
} while( 1 );
if( err != 0 ) {
errno = err;
rc = -1;
}
}
#else
rc = rename(ouri, nuri);
#endif
c_free_locale_string(nuri);
c_free_locale_string(ouri);
return rc;
}
int c_compare_file( const char *f1, const char *f2 ) {
mbchar_t *wf1, *wf2;
int fd1 = -1, fd2 = -1;
size_t size1, size2;
char buffer1[BUFFER_SIZE];
char buffer2[BUFFER_SIZE];
csync_stat_t stat1;
csync_stat_t stat2;
int rc = -1;
if(f1 == NULL || f2 == NULL) return -1;
wf1 = c_utf8_to_locale(f1);
if(wf1 == NULL) {
return -1;
}
wf2 = c_utf8_to_locale(f2);
if(wf2 == NULL) {
c_free_locale_string(wf1);
return -1;
}
#ifdef _WIN32
_fmode = _O_BINARY;
#endif
fd1 = _topen(wf1, O_RDONLY);
if(fd1 < 0) {
rc = -1;
goto out;
}
fd2 = _topen(wf2, O_RDONLY);
if(fd2 < 0) {
rc = -1;
goto out;
}
/* compare size first. */
rc = _tfstat(fd1, &stat1);
if (rc < 0) {
goto out;
}
rc = _tfstat(fd2, &stat2);
if (rc < 0) {
goto out;
}
/* if sizes are different, the files can not be equal. */
if (stat1.st_size != stat2.st_size) {
rc = 0;
goto out;
}
while( (size1 = read(fd1, buffer1, BUFFER_SIZE)) > 0 ) {
size2 = read( fd2, buffer2, BUFFER_SIZE );
if( size1 != size2 ) {
rc = 0;
goto out;
}
if(memcmp(buffer1, buffer2, size1) != 0) {
/* buffers are different */
rc = 0;
goto out;
}
}
rc = 1;
out:
if(fd1 > -1) close(fd1);
if(fd2 > -1) close(fd2);
c_free_locale_string( wf1 );
c_free_locale_string( wf2 );
return rc;
}
+102
Ver Arquivo
@@ -0,0 +1,102 @@
/*
* cynapses libc functions
*
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
* Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file c_file.h
*
* @brief Interface of the cynapses libc file function
*
* @defgroup cynFileInternals cynapses libc file functions
* @ingroup cynLibraryAPI
*
* @{
*/
#ifndef _C_FILE_H
#define _C_FILE_H
#include <sys/types.h>
#include <stdio.h>
#ifndef BUFFER_SIZE
#define BUFFER_SIZE (16 * 1024)
#endif
#ifdef _WIN32
/**
* @brief Check if a path is a link.
*
* @param path The path to check.
*
* @return 1 if the path is a symbolic link, 0 if the path doesn't
* exist or is something else.
*/
int c_islink(const char *path);
#endif
/**
* @brief Check if a path is a regular file or a link.
*
* @param path The path to check.
*
* @return 1 if the path is a file, 0 if the path doesn't exist, is
* something else or can't be accessed.
*/
int c_isfile(const char *path);
/**
* @brief copy a file from source to destination.
*
* @param src Path to the source file
* @param dst Path to the destination file
* @param mode File creation mode of the destination. If mode is 0 then the
* mode from the source will be used.
*
* @return 0 on success, less than 0 on error with errno set.
* EISDIR if src or dst is a file.
*/
int c_copy(const char *src, const char *dst, mode_t mode);
/**
* @brief Compare the content of two files byte by byte.
* @param f1 Path of file 1
* @param f2 Path of file 2
*
* @return 0 if the files differ, 1 if the files are equal or -1 on
* error with errno set.
*/
int c_compare_file( const char *f1, const char *f2 );
/**
* @brief move a file from source to destination.
*
* @param src Path to the source file
* @param dst Path to the destination file
*
* @return 0 on success, less than 0 on error with errno set.
*/
int c_rename( const char *src, const char *dst );
/**
* }@
*/
#endif /* _C_FILE_H */
+36
Ver Arquivo
@@ -23,9 +23,45 @@
#include "c_macro.h"
#include "c_alloc.h"
#include "c_dir.h"
#include "c_file.h"
#include "c_list.h"
#include "c_path.h"
#include "c_rbtree.h"
#include "c_string.h"
#include "c_time.h"
#include "c_private.h"
#ifndef UNIT_TESTING
#ifdef malloc
#undef malloc
#endif
#define malloc(x) DO_NOT_CALL_MALLOC__USE_C_MALLOC_INSTEAD
#ifdef calloc
#undef calloc
#endif
#define calloc(x,y) DO_NOT_CALL_CALLOC__USE_C_CALLOC_INSTEAD
#endif
#ifdef realloc
#undef realloc
#endif
#define realloc(x,y) DO_NOT_CALL_REALLOC__USE_C_REALLOC_INSTEAD
#ifdef dirname
#undef dirname
#endif
#define dirname(x) DO_NOT_CALL_MALLOC__USE_C_DIRNAME_INSTEAD
#ifdef basename
#undef basename
#endif
#define basename(x) DO_NOT_CALL_MALLOC__USE_C_BASENAME_INSTEAD
#ifdef strdup
#undef strdup
#endif
#define strdup(x) DO_NOT_CALL_STRDUP__USE_C_STRDUP_INSTEAD
+156
Ver Arquivo
@@ -117,6 +117,81 @@ char *c_basename (const char *path) {
return newbuf;
}
char *c_tmpname(const char *templ) {
char *tmp = NULL;
char *target = NULL;
int rc;
int i = 0;
if (!templ) {
goto err;
}
/* If the template does not contain the XXXXXX it will be appended. */
if( !strstr( templ, "XXXXXX" )) {
/* split up the path */
char *path = c_dirname(templ);
char *base = c_basename(templ);
if (!base) {
if (path) {
SAFE_FREE(path);
}
goto err;
}
/* Create real hidden files for unixoide. */
if( path ) {
#ifdef _WIN32
rc = asprintf(&target, "%s/%s.~XXXXXX", path, base);
#else
rc = asprintf(&target, "%s/.%s.~XXXXXX", path, base);
#endif
} else {
#ifdef _WIN32
rc = asprintf(&target, "%s.~XXXXXX", base);
#else
rc = asprintf(&target, ".%s.~XXXXXX", base);
#endif
}
SAFE_FREE(path);
SAFE_FREE(base);
if (rc < 0) {
goto err;
}
} else {
target = c_strdup(templ);
}
if (!target) {
goto err;
}
tmp = strstr( target, "XXXXXX" );
if (!tmp) {
goto err;
}
for (i = 0; i < 6; ++i) {
#ifdef _WIN32
/* in win32 MAX_RAND is 32767, thus we can not shift that far,
* otherwise the last three chars are 0
*/
int hexdigit = (rand() >> (i * 2)) & 0x1f;
#else
int hexdigit = (rand() >> (i * 5)) & 0x1f;
#endif
tmp[i] = hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0';
}
return target;
err:
errno = EINVAL;
return NULL;
}
int c_parse_uri(const char *uri,
char **scheme,
char **user, char **passwd,
@@ -395,3 +470,84 @@ int c_parse_uri(const char *uri,
return -1;
}
/*
* http://refactormycode.com/codes/1345-extracting-directory-filename-and-extension-from-a-path
* Allocate a block of memory that holds the PATHINFO at the beginning
* followed by the actual path. Two extra bytes are allocated (+3 instead
* of just +1) to deal with shifting the filename and extension to protect the trailing '/'
* and the leading '.'. These extra bytes also double as the empty string, as
* well as a pad to keep from reading past the memory block.
*
*/
C_PATHINFO * c_split_path(const char* pathSrc)
{
size_t length = strlen(pathSrc);
size_t len=0;
C_PATHINFO * pathinfo = (C_PATHINFO *) c_malloc(sizeof(C_PATHINFO) + length + 3);
if (pathinfo)
{
char * path = (char *) &pathinfo[1]; // copy of the path
char * theEnd = &path[length + 1]; // second null terminator
char * extension;
char * lastSep;
// Copy the original string and double null terminate it.
strcpy(path, pathSrc);
*theEnd = '\0';
pathinfo->directory = theEnd; // Assume no path
pathinfo->extension = theEnd; // Assume no extension
pathinfo->filename = path; // Assume filename only
lastSep = strrchr(path, '/');
if (lastSep)
{
pathinfo->directory = path; // Pick up the path
memmove(lastSep + 1, lastSep, strlen(lastSep));
*lastSep++ ='/';
*lastSep++ ='\0'; // Truncate directory
pathinfo->filename = lastSep; // Pick up name after path
}
// Start at the second character of the filename to handle
// filenames that start with '.' like ".login".
// We don't overrun the buffer in the cases of an empty path
// or a path that looks like "/usr/bin/" because of the extra
// byte.
extension = strrchr(&pathinfo->filename[1], '.');
if (extension)
{
// Shift the extension over to protect the leading '.' since
// we need to truncate the filename.
memmove(extension + 1, extension, strlen(extension));
pathinfo->extension = extension + 1;
*extension = '\0'; // Truncate filename
}
else
{
len=strlen(pathinfo->filename);
if(len>1)
{
//tmp files from kate/kwrite "somefile~": '~' should be the extension
if(pathinfo->filename[len-1]=='~')
{
extension = &pathinfo->filename[len-1];
memmove(extension + 1, extension, strlen(extension));
pathinfo->extension = extension + 1;
*extension = '\0'; // Truncate filename
}
}
}
}
return pathinfo;
}
+22
Ver Arquivo
@@ -66,6 +66,19 @@ char *c_dirname(const char *path);
*/
char *c_basename (const char *path);
/**
* @brief Make a temporary filename.
*
* @param templ The template to replace. If the template contains six X like
* 'XXXXXX', these are replaced by a random string. If not, the
* templ is interpreted as a path, and a name to a hidden file
* with six random is returned.
* The caller has to free the memory.
*
* @return a poitner to the random hidden filename or NULL.
*/
char *c_tmpname(const char *templ);
/**
* @brief parse a uri and split it into components.
*
@@ -107,6 +120,15 @@ typedef struct
char * extension;
} C_PATHINFO;
/**
* @brief Extracting directory, filename and extension from a path.
*
* @param pathSrc The path to parse.
*
* @return Returns a C_PATHINFO structure that should be freed using SAFE_FREE().
*/
C_PATHINFO * c_split_path(const char* pathSrc);
/**
* }@
+63
Ver Arquivo
@@ -239,6 +239,69 @@ void c_strlist_destroy(c_strlist_t *strlist) {
SAFE_FREE(strlist);
}
char *c_strreplace(char *src, const char *pattern, const char *repl) {
char *p = NULL;
while ((p = strstr(src, pattern)) != NULL) {
size_t of = p - src;
size_t l = strlen(src);
size_t pl = strlen(pattern);
size_t rl = strlen(repl);
if (rl > pl) {
src = (char *) c_realloc(src, strlen(src) + rl - pl + 1);
}
if (rl != pl) {
memmove(src + of + rl, src + of + pl, l - of - pl + 1);
}
strncpy(src + of, repl, rl);
}
return src;
}
char *c_uppercase(const char* str) {
char *new;
char *p;
if (str == NULL) {
return NULL;
}
new = c_strdup(str);
if (new == NULL) {
return NULL;
}
for (p = new; *p; p++) {
*p = toupper(*p);
}
return new;
}
char *c_lowercase(const char* str) {
char *new;
char *p;
if (str == NULL) {
return NULL;
}
new = c_strdup(str);
if (new == NULL) {
return NULL;
}
for (p = new; *p; p++) {
*p = tolower(*p);
}
return new;
}
/* Convert a wide multibyte String to UTF8 */
char* c_utf8_from_locale(const mbchar_t *wstr)
{
+31
Ver Arquivo
@@ -119,6 +119,37 @@ void c_strlist_clear(c_strlist_t *strlist);
*/
void c_strlist_destroy(c_strlist_t *strlist);
/**
* @breif Replace a string with another string in a source string.
*
* @param src String to search for pattern.
*
* @param pattern Pattern to search for in the source string.
*
* @param repl The string which which should replace pattern if found.
*
* @return Return a pointer to the source string.
*/
char *c_strreplace(char *src, const char *pattern, const char *repl);
/**
* @brief Uppercase a string.
*
* @param str The String to uppercase.
*
* @return The malloced uppered string or NULL on error.
*/
char *c_uppercase(const char* str);
/**
* @brief Lowercase a string.
*
* @param str The String to lowercase.
*
* @return The malloced lowered string or NULL on error.
*/
char *c_lowercase(const char* str);
/**
* @brief Convert a platform locale string to utf8.
*
+17 -7
Ver Arquivo
@@ -24,7 +24,6 @@
#include <errno.h>
#include <stdio.h>
#include <assert.h>
#include "csync_private.h"
#include "csync_util.h"
@@ -45,7 +44,7 @@ csync_vio_handle_t *csync_vio_opendir(CSYNC *ctx, const char *name) {
if(ctx->remote.read_from_db) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Read from db flag is true, should not!" );
}
return owncloud_opendir(ctx, name);
return owncloud_opendir(name);
break;
case LOCAL_REPLICA:
return csync_vio_local_opendir(name);
@@ -70,7 +69,7 @@ int csync_vio_closedir(CSYNC *ctx, csync_vio_handle_t *dhandle) {
if( ctx->remote.read_from_db ) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Remote ReadFromDb is true, should not!");
}
rc = owncloud_closedir(ctx, dhandle);
rc = owncloud_closedir(dhandle);
break;
case LOCAL_REPLICA:
rc = csync_vio_local_closedir(dhandle);
@@ -88,7 +87,7 @@ csync_vio_file_stat_t *csync_vio_readdir(CSYNC *ctx, csync_vio_handle_t *dhandle
if( ctx->remote.read_from_db ) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Remote readfromdb is true, should not!");
}
return owncloud_readdir(ctx, dhandle);
return owncloud_readdir(dhandle);
break;
case LOCAL_REPLICA:
return csync_vio_local_readdir(dhandle);
@@ -107,8 +106,7 @@ int csync_vio_stat(CSYNC *ctx, const char *uri, csync_vio_file_stat_t *buf) {
switch(ctx->replica) {
case REMOTE_REPLICA:
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "ERROR: Cannot call remote stat, not implemented");
assert(ctx->replica != REMOTE_REPLICA);
rc = owncloud_stat(uri, buf);
break;
case LOCAL_REPLICA:
rc = csync_vio_local_stat(uri, buf);
@@ -123,9 +121,21 @@ int csync_vio_stat(CSYNC *ctx, const char *uri, csync_vio_file_stat_t *buf) {
return rc;
}
char *csync_vio_get_status_string(CSYNC *ctx) {
if(ctx->error_string) {
return ctx->error_string;
}
return owncloud_error_string(ctx);
return owncloud_error_string();
}
int csync_vio_set_property(CSYNC* ctx, const char* key, void* data) {
(void) ctx;
return owncloud_set_property(key, data);
}
int csync_vio_commit(CSYNC *ctx) {
(void) ctx;
return owncloud_commit();
}
+3
Ver Arquivo
@@ -39,7 +39,10 @@ csync_vio_file_stat_t *csync_vio_readdir(CSYNC *ctx, csync_vio_handle_t *dhandle
int csync_vio_stat(CSYNC *ctx, const char *uri, csync_vio_file_stat_t *buf);
int csync_vio_set_property(CSYNC *ctx, const char *key, void *data);
char *csync_vio_get_status_string(CSYNC *ctx);
int csync_vio_commit(CSYNC *ctx);
#endif /* _CSYNC_VIO_H */
+14 -4
Ver Arquivo
@@ -22,8 +22,14 @@
#include "vio/csync_vio_file_stat.h"
csync_vio_file_stat_t *csync_vio_file_stat_new(void) {
csync_vio_file_stat_t *file_stat = (csync_vio_file_stat_t *) c_malloc(sizeof(csync_vio_file_stat_t));
ZERO_STRUCTP(file_stat);
csync_vio_file_stat_t *file_stat = NULL;
file_stat = (csync_vio_file_stat_t *) c_malloc(sizeof(csync_vio_file_stat_t));
if (file_stat == NULL) {
return NULL;
}
file_stat->etag = NULL;
memset(file_stat->file_id, 0, FILE_ID_BUF_SIZE+1);
return file_stat;
}
@@ -33,11 +39,15 @@ void csync_vio_file_stat_destroy(csync_vio_file_stat_t *file_stat) {
return;
}
if (file_stat->fields & CSYNC_VIO_FILE_STAT_FIELDS_SYMLINK_NAME) {
SAFE_FREE(file_stat->u.symlink_name);
}
if (file_stat->fields & CSYNC_VIO_FILE_STAT_FIELDS_CHECKSUM) {
SAFE_FREE(file_stat->u.checksum);
}
if (file_stat->fields & CSYNC_VIO_FILE_STAT_FIELDS_ETAG) {
SAFE_FREE(file_stat->etag);
}
SAFE_FREE(file_stat->directDownloadUrl);
SAFE_FREE(file_stat->directDownloadCookies);
SAFE_FREE(file_stat->name);
SAFE_FREE(file_stat);
}
+26 -21
Ver Arquivo
@@ -34,15 +34,12 @@
#define FILE_ID_BUF_SIZE 21
// currently specified at https://github.com/owncloud/core/issues/8322 are 9 to 10
#define REMOTE_PERM_BUF_SIZE 15
typedef struct csync_vio_file_stat_s csync_vio_file_stat_t;
enum csync_vio_file_flags_e {
CSYNC_VIO_FILE_FLAGS_NONE = 0,
CSYNC_VIO_FILE_FLAGS_SYMLINK = 1 << 0,
CSYNC_VIO_FILE_FLAGS_HIDDEN = 1 << 1
CSYNC_VIO_FILE_FLAGS_LOCAL = 1 << 1
};
enum csync_vio_file_type_e {
@@ -59,44 +56,48 @@ enum csync_vio_file_type_e {
enum csync_vio_file_stat_fields_e {
CSYNC_VIO_FILE_STAT_FIELDS_NONE = 0,
CSYNC_VIO_FILE_STAT_FIELDS_TYPE = 1 << 0,
CSYNC_VIO_FILE_STAT_FIELDS_MODE = 1 << 1, // local POSIX mode
CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS = 1 << 1,
CSYNC_VIO_FILE_STAT_FIELDS_FLAGS = 1 << 2,
CSYNC_VIO_FILE_STAT_FIELDS_DEVICE = 1 << 3,
CSYNC_VIO_FILE_STAT_FIELDS_INODE = 1 << 4,
CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT = 1 << 5,
CSYNC_VIO_FILE_STAT_FIELDS_SIZE = 1 << 6,
// CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_COUNT = 1 << 7, /* will be removed */
// CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_SIZE = 1 << 8, /* will be removed */
CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_COUNT = 1 << 7, /* will be removed */
CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_SIZE = 1 << 8, /* will be removed */
CSYNC_VIO_FILE_STAT_FIELDS_ATIME = 1 << 9,
CSYNC_VIO_FILE_STAT_FIELDS_MTIME = 1 << 10,
CSYNC_VIO_FILE_STAT_FIELDS_CTIME = 1 << 11,
// CSYNC_VIO_FILE_STAT_FIELDS_SYMLINK_NAME = 1 << 12,
// CSYNC_VIO_FILE_STAT_FIELDS_CHECKSUM = 1 << 13,
// CSYNC_VIO_FILE_STAT_FIELDS_ACL = 1 << 14,
// CSYNC_VIO_FILE_STAT_FIELDS_UID = 1 << 15,
// CSYNC_VIO_FILE_STAT_FIELDS_GID = 1 << 16,
CSYNC_VIO_FILE_STAT_FIELDS_SYMLINK_NAME = 1 << 12,
CSYNC_VIO_FILE_STAT_FIELDS_CHECKSUM = 1 << 13,
CSYNC_VIO_FILE_STAT_FIELDS_ACL = 1 << 14,
CSYNC_VIO_FILE_STAT_FIELDS_UID = 1 << 15,
CSYNC_VIO_FILE_STAT_FIELDS_GID = 1 << 16,
CSYNC_VIO_FILE_STAT_FIELDS_ETAG = 1 << 17,
CSYNC_VIO_FILE_STAT_FIELDS_FILE_ID = 1 << 18,
CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADURL = 1 << 19,
CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADCOOKIES = 1 << 20,
CSYNC_VIO_FILE_STAT_FIELDS_PERM = 1 << 21 // remote oC perm
CSYNC_VIO_FILE_STAT_FIELDS_FILE_ID = 1 << 18
};
struct csync_vio_file_stat_s {
union {
char *symlink_name;
char *checksum;
} u;
void *acl;
char *name;
char *etag; // FIXME: Should this be inlined like file_id and perm?
char *etag;
char file_id[FILE_ID_BUF_SIZE+1];
char *directDownloadUrl;
char *directDownloadCookies;
char remotePerm[REMOTE_PERM_BUF_SIZE+1];
uid_t uid;
gid_t gid;
time_t atime;
time_t mtime;
time_t ctime;
int64_t size;
int64_t blksize; /* will be removed in future, not used in csync */
unsigned long blkcount; /* will be removed in future, not used in csync */
mode_t mode;
@@ -108,6 +109,10 @@ struct csync_vio_file_stat_s {
enum csync_vio_file_type_e type;
enum csync_vio_file_flags_e flags;
void *reserved1;
void *reserved2;
void *reserved3;
};
csync_vio_file_stat_t *csync_vio_file_stat_new(void);
+16 -8
Ver Arquivo
@@ -224,10 +224,12 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
buf->type = CSYNC_VIO_FILE_TYPE_REGULAR;
break;
} while (0);
/* TODO Do we want to parse for CSYNC_VIO_FILE_FLAGS_HIDDEN ? */
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FLAGS;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
buf->mode = 666;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS;
buf->device = fileInfo.dwVolumeSerialNumber;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_DEVICE;
@@ -238,7 +240,7 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
/* printf("Index: %I64i\n", FileIndex.QuadPart); */
buf->inode = FileIndex.QuadPart;
buf->size = (fileInfo.nFileSizeHigh * ((int64_t)(MAXDWORD)+1)) + fileInfo.nFileSizeLow;
buf->size = (fileInfo.nFileSizeHigh * (int64_t)(MAXDWORD+1)) + fileInfo.nFileSizeLow;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
/* Get the file time with a win32 call rather than through stat. See
@@ -314,7 +316,7 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
buf->mode = sb.st_mode;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MODE;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS;
if (buf->type == CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK) {
/* FIXME: handle symlink */
@@ -322,11 +324,6 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
} else {
buf->flags = CSYNC_VIO_FILE_FLAGS_NONE;
}
#ifdef __APPLE__
if (sb.st_flags & UF_HIDDEN) {
buf->flags |= CSYNC_VIO_FILE_FLAGS_HIDDEN;
}
#endif
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FLAGS;
buf->device = sb.st_dev;
@@ -335,6 +332,11 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
buf->inode = sb.st_ino;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_INODE;
/* Both values are only initialized to zero as they are not used in csync */
/* They are deprecated and will be rmemoved later. */
buf->blksize = 0;
buf->blkcount = 0;
buf->atime = sb.st_atime;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME;
@@ -347,6 +349,12 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
buf->nlink = sb.st_nlink;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT;
buf->uid = sb.st_uid;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_UID;
buf->gid = sb.st_gid;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_GID;
buf->size = sb.st_size;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
+2
Ver Arquivo
@@ -21,6 +21,8 @@ set(TEST_TARGET_LIBRARIES ${TORTURE_LIBRARY})
# std
add_cmocka_test(check_std_c_alloc std_tests/check_std_c_alloc.c ${TEST_TARGET_LIBRARIES})
add_cmocka_test(check_std_c_dir std_tests/check_std_c_dir.c ${TEST_TARGET_LIBRARIES})
add_cmocka_test(check_std_c_file std_tests/check_std_c_file.c ${TEST_TARGET_LIBRARIES})
add_cmocka_test(check_std_c_jhash std_tests/check_std_c_jhash.c ${TEST_TARGET_LIBRARIES})
add_cmocka_test(check_std_c_list std_tests/check_std_c_list.c ${TEST_TARGET_LIBRARIES})
add_cmocka_test(check_std_c_path std_tests/check_std_c_path.c ${TEST_TARGET_LIBRARIES})
@@ -36,6 +36,9 @@ static void setup(void **state) {
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
assert_int_equal(rc, 0);
rc = csync_set_config_dir(csync, "/tmp/check_csync");
assert_int_equal(rc, 0);
*state = csync;
}
@@ -52,6 +55,9 @@ static void setup_module(void **state) {
rc = csync_create(&csync, "/tmp/check_csync1", "dummy://foo/bar");
assert_int_equal(rc, 0);
rc = csync_set_config_dir(csync, "/tmp/check_csync");
assert_int_equal(rc, 0);
rc = csync_init(csync);
*state = csync;
}
@@ -38,6 +38,7 @@ static void check_csync_destroy_null(void **state)
static void check_csync_create(void **state)
{
CSYNC *csync;
char confdir[1024] = {0};
int rc;
(void) state; /* unused */
@@ -45,6 +46,9 @@ static void check_csync_create(void **state)
rc = csync_create(&csync, "/tmp/csync1", "/tmp/csync2");
assert_int_equal(rc, 0);
snprintf(confdir, sizeof(confdir), "%s/%s", getenv("HOME"), CSYNC_CONF_DIR);
assert_string_equal(csync->options.config_dir, confdir);
rc = csync_destroy(csync);
assert_int_equal(rc, 0);
}
@@ -32,6 +32,10 @@ static void setup(void **state) {
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
assert_int_equal(rc, 0);
free(csync->options.config_dir);
csync->options.config_dir = c_strdup("/tmp/check_csync1/");
assert_non_null(csync->options.config_dir);
*state = csync;
}
@@ -42,6 +46,10 @@ static void setup_init(void **state) {
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
assert_int_equal(rc, 0);
free(csync->options.config_dir);
csync->options.config_dir = c_strdup("/tmp/check_csync1/");
assert_non_null(csync->options.config_dir);
rc = csync_exclude_load(csync, SOURCEDIR "/../sync-exclude.lst");
assert_int_equal(rc, 0);
+6
Ver Arquivo
@@ -36,6 +36,9 @@ static void setup(void **state) {
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
assert_int_equal(rc, 0);
rc = csync_set_config_dir(csync, "/tmp/check_csync");
assert_int_equal(rc, 0);
*state = csync;
}
@@ -52,6 +55,9 @@ static void setup_module(void **state) {
rc = csync_create(&csync, "/tmp/check_csync1", "dummy://foo/bar");
assert_int_equal(rc, 0);
rc = csync_set_config_dir(csync, "/tmp/check_csync");
assert_int_equal(rc, 0);
*state = csync;
}
+3
Ver Arquivo
@@ -40,6 +40,9 @@ static void setup(void **state) {
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
assert_int_equal(rc, 0);
rc = csync_set_config_dir(csync, "/tmp/check_csync");
assert_int_equal(rc, 0);
*state = csync;
}
@@ -40,6 +40,8 @@ static void setup(void **state) {
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
assert_int_equal(rc, 0);
csync_set_config_dir(csync, "/tmp/check_csync1/");
csync->statedb.file = c_strdup( TESTDB );
*state = csync;
}
@@ -44,6 +44,8 @@ static void setup(void **state)
assert_int_equal(rc, 0);
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
assert_int_equal(rc, 0);
rc = csync_set_config_dir(csync, "/tmp/check_csync/");
assert_int_equal(rc, 0);
rc = csync_init(csync);
assert_int_equal(rc, 0);
+17
Ver Arquivo
@@ -36,6 +36,8 @@ static void setup(void **state)
assert_int_equal(rc, 0);
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
assert_int_equal(rc, 0);
rc = csync_set_config_dir(csync, "/tmp/check_csync");
assert_int_equal(rc, 0);
rc = csync_init(csync);
assert_int_equal(rc, 0);
rc = csync_statedb_load(csync, TESTDB, &csync->statedb.db);
@@ -58,6 +60,8 @@ static void setup_ftw(void **state)
assert_int_equal(rc, 0);
rc = csync_create(&csync, "/tmp", "/tmp");
assert_int_equal(rc, 0);
rc = csync_set_config_dir(csync, "/tmp/check_csync");
assert_int_equal(rc, 0);
rc = csync_init(csync);
assert_int_equal(rc, 0);
rc = csync_statedb_load(csync, TESTDB, &csync->statedb.db);
@@ -120,6 +124,8 @@ static csync_vio_file_stat_t* create_fstat(const char *name,
fs->type = CSYNC_VIO_FILE_TYPE_REGULAR;
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
fs->mode = 0644;
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS;
if (inode == 0) {
fs->inode = 619070;
@@ -140,6 +146,17 @@ static csync_vio_file_stat_t* create_fstat(const char *name,
}
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT;
fs->uid = 1000;
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_UID;
fs->gid = 1000;
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_GID;
fs->blkcount = 312;
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_COUNT;
fs->blksize = 4096;
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_SIZE;
if (mtime == 0) {
fs->atime = fs->ctime = fs->mtime = time(&t);
-11
Ver Arquivo
@@ -46,7 +46,6 @@ glob_put( 'toremote1/rtl1/rtl11/*', "remoteToLocal1/rtl1/rtl11/" );
glob_put( 'toremote1/rtl2/*', "remoteToLocal1/rtl2/" );
glob_put( 'toremote1/rtl4/*', "remoteToLocal1/rtl4/" );
# call csync, sync local t1 to remote t1
csync();
@@ -75,19 +74,9 @@ foreach my $file ( <./tolocal1/*> ) {
print "Copying $file to $locDir\n";
copy( $file, $locDir );
}
# Also add a file with symbols
my $symbolName = "a\%b#c\$d-e";
system( "echo \"my symbols\" >> $locDir/$symbolName" );
#Also on the server
put_to_dir( "$locDir/$symbolName", 'remoteToLocal1' );
csync( );
print "\nAssert local and remote dirs.\n";
assertLocalAndRemoteDir( '', 0);
assert( ! -e localDir().$symbolName );
# move a local file
printInfo( "Move a file locally." );
+1 -23
Ver Arquivo
@@ -185,34 +185,12 @@ assertLocalAndRemoteDir( 'remoteToLocal1', 1);
printInfo("Move a file from the server");
$inode = getInode('remoteToLocal1/rtl2/kb1_local_gone.jpg');
moveRemoteFile( 'remoteToLocal1/rtl2/kb1_local_gone.jpg', 'remoteToLocal1/rtl2/kb1_local_gone2.jpg');
#also create a new directory localy for the next test
mkdir( localDir().'superNewDir' );
createLocalFile(localDir(). 'superNewDir/f1', 1234 );
createLocalFile(localDir(). 'superNewDir/f2', 1324 );
my $superNewDirInode = getInode('superNewDir');
csync();
assertLocalAndRemoteDir( '', 1);
assertLocalAndRemoteDir( 'remoteToLocal1', 1);
$inode2 = getInode('remoteToLocal1/rtl2/kb1_local_gone2.jpg');
assert( $inode == $inode2, "Inode has changed 3!");
printInfo("Move a newly created directory");
moveRemoteFile('superNewDir', 'superNewDirRenamed');
#also add new files in new directory
createLocalFile(localDir(). 'superNewDir/f3' , 2456 );
$inode = getInode('superNewDir/f3');
csync();
assertLocalAndRemoteDir( '', 1);
assert( ! -e localDir().'superNewDir' );
$inode2 = getInode('superNewDir/f3');
assert( $inode == $inode2, "Inode of f3 changed");
$inode2 = getInode('superNewDir');
assert( $superNewDirInode == $inode2, "Inode of superNewDir changed");
cleanup();
-10
Ver Arquivo
@@ -67,13 +67,6 @@ system( "rm -rf " . localDir() . 'remoteToLocal1' );
system( "echo \"my file\" >> /tmp/myfile.txt" );
put_to_dir( '/tmp/myfile.txt', 'remoteToLocal1/rtl1/rtl11' );
# Also add a file with symbols
my $symbolName = "a\%b#c\$d-e";
system( "echo \"my symbols\" >> /tmp/$symbolName" );
put_to_dir( "/tmp/$symbolName", 'remoteToLocal1/rtl1/rtl11' );
my $fileid = remoteFileId( 'remoteToLocal1/rtl1/', 'rtl11' );
my $fid2 = remoteFileId( 'remoteToLocal1/rtl1/', 'La ced' );
assert($fid2 eq "" or $fileid ne $fid2, "File IDs are equal" );
@@ -97,9 +90,6 @@ printInfo("Move file and create another one with the same name.");
move( localDir() . 'newdir/myfile.txt', localDir() . 'newdir/oldfile.txt' );
system( "echo \"super new\" >> " . localDir() . 'newdir/myfile.txt' );
#Move a file with symbols as well
move( localDir() . "newdir/$symbolName", localDir() . "newdir/$symbolName.new" );
#Add some files for the next test.
system( "echo \"un\" > " . localDir() . '1.txt' );
system( "echo \"deux\" > " . localDir() . '2.txt' );
+1
Ver Arquivo
@@ -30,6 +30,7 @@ use ownCloud::Test;
use strict;
print "Hello, this is t5, a tester for syncing of files in Shares\n";
# stat error occours on windsows when the file is busy for example
initTesting();
-256
Ver Arquivo
@@ -1,256 +0,0 @@
#!/usr/bin/perl
#
# Test script for the ownCloud module of csync.
# This script requires a running ownCloud instance accessible via HTTP.
# It does quite some fancy tests and asserts the results.
#
# Copyright (C) by Klaas Freitag <freitag@owncloud.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
use lib ".";
use Carp::Assert;
use File::Copy;
use ownCloud::Test;
use strict;
print "Hello, this is t7, a tester for syncing of files in read only directory\n";
# Check if the expected rows in the DB are non-empty. Note that in some cases they might be, then we cannot use this function
# https://github.com/owncloud/mirall/issues/2038
sub assertCsyncJournalOk {
my $path = $_[0];
# FIXME: should test also remoteperm but it's not working with owncloud6
# my $cmd = 'sqlite3 ' . $path . '.csync_journal.db "SELECT count(*) from metadata where length(remotePerm) == 0 or length(fileId) == 0"';
my $cmd = 'sqlite3 ' . $path . '.csync_journal.db "SELECT count(*) from metadata where length(fileId) == 0"';
my $result = `$cmd`;
assert($result == "0");
}
# IMPORTANT NOTE :
print "This test use the OWNCLOUD_TEST_PERMISSIONS environement variable and _PERM_xxx_ on filenames to set the permission. ";
print "It does not rely on real permission set on the server. This test is just for testing the propagation choices\n";
# "It would be nice" to have a test that test with real permissions on the server
$ENV{OWNCLOUD_TEST_PERMISSIONS} = "1";
initTesting();
printInfo( "Init" );
#create some files localy
my $tmpdir = "/tmp/t7/";
mkdir($tmpdir);
createLocalFile( $tmpdir . "normalFile_PERM_WVND_.data", 100 );
createLocalFile( $tmpdir . "cannotBeRemoved_PERM_WVN_.data", 101 );
createLocalFile( $tmpdir . "canBeRemoved_PERM_D_.data", 102 );
my $md5CanotBeModified = createLocalFile( $tmpdir . "canotBeModified_PERM_DVN_.data", 103 );
createLocalFile( $tmpdir . "canBeModified_PERM_W_.data", 104 );
#put them in some directories
createRemoteDir( "normalDirectory_PERM_CKDNV_" );
glob_put( "$tmpdir/*", "normalDirectory_PERM_CKDNV_" );
createRemoteDir( "readonlyDirectory_PERM_M_" );
glob_put( "$tmpdir/*", "readonlyDirectory_PERM_M_" );
createRemoteDir( "readonlyDirectory_PERM_M_/subdir_PERM_CK_" );
createRemoteDir( "readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_" );
glob_put( "$tmpdir/normalFile_PERM_WVND_.data", "readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_" );
csync();
assertCsyncJournalOk(localDir());
assertLocalAndRemoteDir( '', 0);
system("sleep 1"); #make sure changes have different mtime
printInfo( "Do some changes and see how they propagate" );
#1. remove the file than cannot be removed
# (they should be recovered)
unlink( localDir() . 'normalDirectory_PERM_CKDNV_/cannotBeRemoved_PERM_WVN_.data' );
unlink( localDir() . 'readonlyDirectory_PERM_M_/cannotBeRemoved_PERM_WVN_.data' );
#2. remove the file that can be removed
# (they should properly be gone)
unlink( localDir() . 'normalDirectory_PERM_CKDNV_/canBeRemoved_PERM_D_.data' );
unlink( localDir() . 'readonlyDirectory_PERM_M_/canBeRemoved_PERM_D_.data' );
#3. Edit the files that cannot be modified
# (they should be recovered, and a conflict shall be created)
system("echo 'modified' > ". localDir() . "normalDirectory_PERM_CKDNV_/canotBeModified_PERM_DVN_.data");
system("echo 'modified_' > ". localDir() . "readonlyDirectory_PERM_M_/canotBeModified_PERM_DVN_.data");
#4. Edit other files
# (they should be uploaded)
system("echo '__modified' > ". localDir() . "normalDirectory_PERM_CKDNV_/canBeModified_PERM_W_.data");
system("echo '__modified_' > ". localDir() . "readonlyDirectory_PERM_M_/canBeModified_PERM_W_.data");
#5. Create a new file in a read only folder
# (they should not be uploaded)
createLocalFile( localDir() . "readonlyDirectory_PERM_M_/newFile_PERM_WDNV_.data", 105 );
#6. Create a new file in a read only folder
# (should be uploaded)
createLocalFile( localDir() . "normalDirectory_PERM_CKDNV_/newFile_PERM_WDNV_.data", 106 );
#do the sync
csync();
assertCsyncJournalOk(localDir());
#1.
# File should be recovered
assert( -e localDir(). 'normalDirectory_PERM_CKDNV_/cannotBeRemoved_PERM_WVN_.data' );
assert( -e localDir(). 'readonlyDirectory_PERM_M_/cannotBeRemoved_PERM_WVN_.data' );
#2.
# File should be deleted
assert( !-e localDir() . 'normalDirectory_PERM_CKDNV_/canBeRemoved_PERM_D_.data' );
assert( !-e localDir() . 'readonlyDirectory_PERM_M_/canBeRemoved_PERM_D_.data' );
#3.
# File should be recovered
assert($md5CanotBeModified eq md5OfFile( localDir().'normalDirectory_PERM_CKDNV_/canotBeModified_PERM_DVN_.data' ));
assert($md5CanotBeModified eq md5OfFile( localDir().'readonlyDirectory_PERM_M_/canotBeModified_PERM_DVN_.data' ));
# and conflict created
# TODO check that the conflict file has the right content
assert( -e glob(localDir().'normalDirectory_PERM_CKDNV_/canotBeModified_PERM_DVN__conflict-*.data' ) );
assert( -e glob(localDir().'readonlyDirectory_PERM_M_/canotBeModified_PERM_DVN__conflict-*.data' ) );
# remove the conflicts for the next assertLocalAndRemoteDir
system("rm " . localDir().'normalDirectory_PERM_CKDNV_/canotBeModified_PERM_DVN__conflict-*.data' );
system("rm " . localDir().'readonlyDirectory_PERM_M_/canotBeModified_PERM_DVN__conflict-*.data' );
#4. File should be updated, that's tested by assertLocalAndRemoteDir
#5.
# The file should not exist on the remote
# TODO: test that the file is NOT on the server
# but still be there
assert( -e localDir() . "readonlyDirectory_PERM_M_/newFile_PERM_WDNV_.data" );
# remove it so assertLocalAndRemoteDir succeed.
unlink(localDir() . "readonlyDirectory_PERM_M_/newFile_PERM_WDNV_.data");
#6.
# the file should be in the server and local
assert( -e localDir() . "normalDirectory_PERM_CKDNV_/newFile_PERM_WDNV_.data" );
### Both side should still be the same
assertLocalAndRemoteDir( '', 0);
#######################################################################
printInfo( "remove the read only directory" );
# -> It must be recovered
system("rm -r " . localDir().'readonlyDirectory_PERM_M_' );
csync();
assertCsyncJournalOk(localDir());
assert( -e localDir(). 'readonlyDirectory_PERM_M_/cannotBeRemoved_PERM_WVN_.data' );
assert( -e localDir(). 'readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data' );
assertLocalAndRemoteDir( '', 0);
#######################################################################
printInfo( "move a directory in a outside read only folder" );
system("sqlite3 " . localDir().'.csync_journal.db .dump');
#Missing directory should be restored
#new directory should be uploaded
system("mv " . localDir().'readonlyDirectory_PERM_M_/subdir_PERM_CK_ ' . localDir().'normalDirectory_PERM_CKDNV_/subdir_PERM_CKDNV_' );
# two syncs may be necessary for now: https://github.com/owncloud/mirall/issues/2038
csync();
csync();
system("sqlite3 " . localDir().'.csync_journal.db .dump');
assertCsyncJournalOk(localDir());
# old name restored
assert( -e localDir(). 'readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_/' );
assert( -e localDir(). 'readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data' );
# new still exist
assert( -e localDir(). 'normalDirectory_PERM_CKDNV_/subdir_PERM_CKDNV_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data' );
assertLocalAndRemoteDir( '', 0);
#######################################################################
printInfo( "rename a directory in a read only folder and move a directory to a read-only" );
# do a sync to update the database
csync();
#1. rename a directory in a read only folder
#Missing directory should be restored
#new directory should stay but not be uploaded
system("mv " . localDir().'readonlyDirectory_PERM_M_/subdir_PERM_CK_ ' . localDir().'readonlyDirectory_PERM_M_/newname_PERM_CK_' );
#2. move a directory from read to read only (move the directory from previous step)
system("mv " . localDir().'normalDirectory_PERM_CKDNV_/subdir_PERM_CKDNV_ ' . localDir().'readonlyDirectory_PERM_M_/moved_PERM_CK_' );
# two syncs may be necessary for now: https://github.com/owncloud/mirall/issues/2038
csync();
csync();
assertCsyncJournalOk(localDir());
#1.
# old name restored
assert( -e localDir(). 'readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data' );
# new still exist
assert( -e localDir(). 'readonlyDirectory_PERM_M_/newname_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data' );
# but is not on server: so remove for assertLocalAndRemoteDir
system("rm -r " . localDir(). "readonlyDirectory_PERM_M_/newname_PERM_CK_");
#2.
# old removed
assert( ! -e localDir(). 'normalDirectory_PERM_CKDNV_/subdir_PERM_CKDNV_/' );
# new still there
assert( -e localDir(). 'readonlyDirectory_PERM_M_/moved_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data' );
#but not on server
system("rm -r " . localDir(). "readonlyDirectory_PERM_M_/moved_PERM_CK_");
assertLocalAndRemoteDir( '', 0);
system("sqlite3 " . localDir().'.csync_journal.db .dump');
cleanup();
+176
Ver Arquivo
@@ -0,0 +1,176 @@
/*
* libcsync -- a library to sync a directory with another
*
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "torture.h"
#include "std/c_private.h"
#include "std/c_dir.h"
#include "std/c_string.h"
const char *check_dir = "/tmp/check/c_mkdirs//with/check//";
const char *check_file = "/tmp/check/c_mkdirs/with/check/foobar.txt";
static void setup(void **state) {
int rc;
(void) state; /* unused */
rc = c_mkdirs(check_dir, 0755);
assert_int_equal(rc, 0);
rc = system("touch /tmp/check/c_mkdirs/with/check/foobar.txt");
assert_int_equal(rc, 0);
}
static void teardown(void **state) {
int rc;
(void) state; /* unused */
rc = c_rmdirs(check_dir);
assert_int_equal(rc, 0);
}
static int test_dir(const char *path, mode_t mode) {
csync_stat_t sb;
if (lstat(path, &sb) < 0) {
return -1;
}
if (! S_ISDIR(sb.st_mode)) {
return -1;
}
/* FIXME */
if ((sb.st_mode & mode) == mode) {
return 0;
}
return -1;
}
static void check_c_mkdirs_rmdirs(void **state)
{
csync_stat_t sb;
int rc;
mbchar_t *wcheck_dir;
(void) state; /* unused */
rc = c_mkdirs(check_dir, 0755);
assert_int_equal(rc, 0);
rc = test_dir(check_dir, 0755);
assert_int_equal(rc, 0);
rc = c_rmdirs(check_dir);
assert_int_equal(rc, 0);
wcheck_dir = c_utf8_to_locale(check_dir);
rc = _tstat(wcheck_dir, &sb);
c_free_locale_string(wcheck_dir);
assert_int_equal(rc, -1);
}
static void check_c_mkdirs_mode(void **state)
{
csync_stat_t sb;
int rc;
mbchar_t *wcheck_dir;
(void) state; /* unused */
rc = c_mkdirs(check_dir, 0700);
assert_int_equal(rc, 0);
rc = test_dir(check_dir, 0700);
assert_int_equal(rc, 0);
rc = c_rmdirs(check_dir);
assert_int_equal(rc, 0);
wcheck_dir = c_utf8_to_locale(check_dir);
rc = _tstat(wcheck_dir, &sb);
assert_int_equal(rc, -1);
c_free_locale_string(wcheck_dir);
}
static void check_c_mkdirs_existing_path(void **state)
{
int rc;
(void) state; /* unused */
rc = c_mkdirs(check_dir, 0755);
assert_int_equal(rc, 0);
}
static void check_c_mkdirs_file(void **state)
{
int rc;
(void) state; /* unused */
rc = c_mkdirs(check_file, 0755);
assert_int_equal(rc, -1);
assert_int_equal(errno, ENOTDIR);
}
static void check_c_mkdirs_null(void **state)
{
(void) state; /* unused */
assert_int_equal(c_mkdirs(NULL, 0755), -1);
}
static void check_c_isdir(void **state)
{
(void) state; /* unused */
assert_int_equal(c_isdir(check_dir), 1);
}
static void check_c_isdir_on_file(void **state)
{
(void) state; /* unused */
assert_int_equal(c_isdir(check_file), 0);
}
static void check_c_isdir_null(void **state)
{
(void) state; /* unused */
assert_int_equal(c_isdir(NULL), 0);
}
int torture_run_tests(void)
{
const UnitTest tests[] = {
unit_test(check_c_mkdirs_rmdirs),
unit_test(check_c_mkdirs_mode),
unit_test_setup_teardown(check_c_mkdirs_existing_path, setup, teardown),
unit_test_setup_teardown(check_c_mkdirs_file, setup, teardown),
unit_test(check_c_mkdirs_null),
unit_test_setup_teardown(check_c_isdir, setup, teardown),
unit_test_setup_teardown(check_c_isdir_on_file, setup, teardown),
unit_test(check_c_isdir_null),
};
return run_tests(tests);
}
+180
Ver Arquivo
@@ -0,0 +1,180 @@
/*
* libcsync -- a library to sync a directory with another
*
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "torture.h"
#include "std/c_private.h"
#include "std/c_file.h"
#include "std/c_string.h"
const char *check_dir = "/tmp/check";
const char *check_src_file = "/tmp/check/foo.txt";
const char *check_dst_file = "/tmp/check/bar.txt";
static int test_file(const char *path, mode_t mode) {
csync_stat_t sb;
mbchar_t *mbpath = c_utf8_to_locale(path);
int rc = _tstat(mbpath, &sb);
c_free_locale_string(mbpath);
if (rc < 0) {
return -1;
}
if (! S_ISREG(sb.st_mode)) {
return -1;
}
if ((sb.st_mode & mode) == mode) {
return 0;
}
return -1;
}
static void setup(void **state) {
int rc;
(void) state; /* unused */
rc = system("mkdir -p /tmp/check");
assert_int_equal(rc, 0);
rc = system("echo 42 > /tmp/check/foo.txt");
assert_int_equal(rc, 0);
}
static void teardown(void **state) {
int rc;
(void) state; /* unused */
rc = system("rm -rf /tmp/check");
assert_int_equal(rc, 0);
}
static void check_c_copy(void **state)
{
int rc;
(void) state; /* unused */
rc = c_copy(check_src_file, check_dst_file, 0644);
assert_int_equal(rc, 0);
rc = test_file(check_dst_file, 0644);
assert_int_equal(rc, 0);
}
static void check_c_copy_same_file(void **state)
{
int rc;
(void) state; /* unused */
rc = c_copy(check_src_file, check_src_file, 0644);
assert_int_equal(rc, -1);
}
static void check_c_copy_isdir(void **state)
{
int rc;
(void) state; /* unused */
rc = c_copy(check_src_file, check_dir, 0644);
assert_int_equal(rc, -1);
assert_int_equal(errno, EISDIR);
rc = c_copy(check_dir, check_dst_file, 0644);
assert_int_equal(rc, -1);
assert_int_equal(errno, ENOENT);
}
static void check_c_compare_file(void **state)
{
int rc;
(void) state;
rc = c_copy(check_src_file, check_dst_file, 0644);
assert_int_equal(rc, 0);
rc = c_compare_file( check_src_file, check_dst_file );
assert_int_equal(rc, 1);
/* Check error conditions */
rc = c_compare_file( NULL, check_dst_file );
assert_int_equal(rc, -1);
rc = c_compare_file( check_dst_file, NULL );
assert_int_equal(rc, -1);
rc = c_compare_file( NULL, NULL );
assert_int_equal(rc, -1);
rc = c_compare_file( check_src_file, "/I_do_not_exist_in_the_filesystem.dummy");
assert_int_equal(rc, -1);
rc = c_compare_file( "/I_do_not_exist_in_the_filesystem.dummy", check_dst_file);
assert_int_equal(rc, -1);
rc = system("echo \"hallo42\" > /tmp/check/foo.txt");
assert_int_equal(rc, 0);
rc = system("echo \"hallo52\" > /tmp/check/bar.txt");
assert_int_equal(rc, 0);
rc = c_compare_file( check_src_file, check_dst_file );
assert_int_equal(rc, 0);
/* Create two 1MB random files */
rc = system("dd if=/dev/urandom of=/tmp/check/foo.txt bs=1024 count=1024");
assert_int_equal(rc, 0);
rc = system("dd if=/dev/urandom of=/tmp/check/bar.txt bs=1024 count=1024");
assert_int_equal(rc, 0);
rc = c_compare_file( check_src_file, check_dst_file );
assert_int_equal(rc, 0);
/* Create two 1MB random files with different size */
rc = system("dd if=/dev/urandom of=/tmp/check/foo.txt bs=1024 count=1024");
assert_int_equal(rc, 0);
rc = system("dd if=/dev/urandom of=/tmp/check/bar.txt bs=1024 count=1020");
assert_int_equal(rc, 0);
rc = c_compare_file( check_src_file, check_dst_file );
assert_int_equal(rc, 0);
/* compare two big files which are equal */
rc = c_copy(check_src_file, check_dst_file, 0644);
assert_int_equal(rc, 0);
rc = c_compare_file( check_src_file, check_dst_file );
assert_int_equal(rc, 1);
}
int torture_run_tests(void)
{
const UnitTest tests[] = {
unit_test_setup_teardown(check_c_copy, setup, teardown),
unit_test(check_c_copy_same_file),
unit_test_setup_teardown(check_c_copy_isdir, setup, teardown),
unit_test_setup_teardown(check_c_compare_file, setup, teardown),
};
return run_tests(tests);
}
+27
Ver Arquivo
@@ -130,6 +130,32 @@ static void check_c_dirname_uri(void **state)
free(dname);
}
static void check_c_tmpname(void **state)
{
char tmpl[22]={0};
char prev[22]={0};
char *tmp;
int i = 0;
(void) state; /* unused */
srand((unsigned)time(NULL));
/* remember the last random value and compare the new one against.
* They may never be the same. */
for(i = 0; i < 100; i++){
strcpy(tmpl, "check_tmpname.XXXXXX");
tmp = c_tmpname(tmpl);
assert_non_null(tmp);
if (strlen(prev)) {
assert_string_not_equal(tmp, prev);
}
strcpy(prev, tmp);
SAFE_FREE(tmp);
}
}
static void check_c_parse_uri(void **state)
{
const char *test_scheme = "git+ssh";
@@ -178,6 +204,7 @@ int torture_run_tests(void)
unit_test(check_c_dirname),
unit_test(check_c_dirname_uri),
unit_test(check_c_parse_uri),
unit_test(check_c_tmpname),
};
return run_tests(tests);
+86
Ver Arquivo
@@ -113,6 +113,85 @@ static void check_c_strlist_expand(void **state)
c_strlist_destroy(strlist);
}
static void check_c_strreplace(void **state)
{
char *str = strdup("/home/%(USER)");
(void) state; /* unused */
str = c_strreplace(str, "%(USER)", "csync");
assert_string_equal(str, "/home/csync");
free(str);
}
static void check_c_lowercase(void **state)
{
char *str;
(void) state; /* unused */
str = c_lowercase("LoWeRcASE");
assert_string_equal(str, "lowercase");
free(str);
}
static void check_c_lowercase_empty(void **state)
{
char *str;
(void) state; /* unused */
str = c_lowercase("");
assert_string_equal(str, "");
free(str);
}
static void check_c_lowercase_null(void **state)
{
char *str;
(void) state; /* unused */
str = c_lowercase(NULL);
assert_null(str);
}
static void check_c_uppercase(void **state)
{
char *str;
(void) state; /* unused */
str = c_uppercase("upperCASE");
assert_string_equal(str, "UPPERCASE");
free(str);
}
static void check_c_uppercase_empty(void **state)
{
char *str;
(void) state; /* unused */
str = c_uppercase("");
assert_string_equal(str, "");
free(str);
}
static void check_c_uppercase_null(void **state)
{
char *str;
(void) state; /* unused */
str = c_uppercase(NULL);
assert_null(str);
}
int torture_run_tests(void)
@@ -124,6 +203,13 @@ int torture_run_tests(void)
unit_test(check_c_strlist_new),
unit_test(check_c_strlist_add),
unit_test(check_c_strlist_expand),
unit_test(check_c_strreplace),
unit_test(check_c_lowercase),
unit_test(check_c_lowercase_empty),
unit_test(check_c_lowercase_null),
unit_test(check_c_uppercase),
unit_test(check_c_uppercase_empty),
unit_test(check_c_uppercase_null),
};
return run_tests(tests);
+1 -1
Ver Arquivo
@@ -4,7 +4,7 @@ if(SPHINX_FOUND)
set(SPHINX_CACHE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_doctrees")
# HTML output directory
set(SPHINX_HTML_DIR "${CMAKE_CURRENT_BINARY_DIR}/html")
set(SPHINX_MAN_DIR "${CMAKE_CURRENT_BINARY_DIR}/man1")
set(SPHINX_MAN_DIR "${CMAKE_CURRENT_BINARY_DIR}/man")
set(SPHINX_PDF_DIR "${CMAKE_CURRENT_BINARY_DIR}/latex")
set(SPHINX_QCH_DIR "${CMAKE_CURRENT_BINARY_DIR}/qthelp")
set(SPHINX_HTMLHELP_DIR "${CMAKE_CURRENT_BINARY_DIR}/htmlhelp")
-3
Ver Arquivo
@@ -86,7 +86,6 @@ set(libsync_SRCS
mirall/mirallconfigfile.cpp
mirall/syncengine.cpp
mirall/owncloudpropagator.cpp
mirall/bandwidthmanager.cpp
mirall/propagatorjobs.cpp
mirall/propagator_qnam.cpp
mirall/propagator_legacy.cpp
@@ -356,9 +355,7 @@ ENDIF()
include_directories(../csync/src ../csync/src/httpbf/src ${CMAKE_CURRENT_BINARY_DIR}/../csync ${CMAKE_CURRENT_BINARY_DIR}/../csync/src )
include_directories(${3rdparty_INC})
if(NOT TOKEN_AUTH_ONLY)
qt_add_translation(mirall_I18N ${TRANSLATIONS})
endif()
set( final_src
${mirall_HEADERS}
+4 -3
Ver Arquivo
@@ -48,9 +48,8 @@ int getauth(const char *prompt,
void *userdata)
{
int re = 0;
// ### safe? Not really. If the wizard is run in the main thread, the caccount could change during the sync.
// Ideally, http_credentials could be use userdata, but userdata is the SyncEngine.
QMutex mutex;
// ### safe?
HttpCredentials* http_credentials = qobject_cast<HttpCredentials*>(AccountManager::instance()->account()->credentials());
if (!http_credentials) {
@@ -64,8 +63,10 @@ int getauth(const char *prompt,
if( qPrompt == QLatin1String("Enter your username:") ) {
// qDebug() << "OOO Username requested!";
QMutexLocker locker( &mutex );
qstrncpy( buf, user.toUtf8().constData(), len );
} else if( qPrompt == QLatin1String("Enter your password:") ) {
QMutexLocker locker( &mutex );
// qDebug() << "OOO Password requested!";
qstrncpy( buf, pwd.toUtf8().constData(), len );
} else {
+1 -1
Ver Arquivo
@@ -405,7 +405,7 @@ void ShibbolethCredentials::showLoginWindow(Account* account)
QList<QNetworkCookie> ShibbolethCredentials::accountCookies(Account *account)
{
return account->networkAccessManager()->cookieJar()->cookiesForUrl(account->url());
return account->networkAccessManager()->cookieJar()->cookiesForUrl(account->davUrl());
}
QNetworkCookie ShibbolethCredentials::findShibCookie(Account *account, QList<QNetworkCookie> cookies)
+23 -20
Ver Arquivo
@@ -17,7 +17,6 @@
#include <QDebug>
#include <QNetworkReply>
#include <QSettings>
#include <QNetworkCookieJar>
#include "mirall/account.h"
#include "mirall/mirallaccessmanager.h"
@@ -80,19 +79,11 @@ public:
: MirallAccessManager(parent), _cred(cred) {}
protected:
QNetworkReply *createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData) {
if (_cred->user().isEmpty() || _cred->password().isEmpty() || _cred->_token.isEmpty()) {
qWarning() << Q_FUNC_INFO << "Empty user/password/token provided!";
}
QNetworkRequest req(request);
QByteArray credHash = QByteArray(_cred->user().toUtf8()+":"+_cred->password().toUtf8()).toBase64();
QNetworkRequest req(request);
req.setRawHeader(QByteArray("Authorization"), QByteArray("Basic ") + credHash);
// A pre-authenticated cookie
QByteArray token = _cred->_token.toUtf8();
setRawCookie(token, request.url());
//qDebug() << "Request for " << req.url() << "with authorization" << QByteArray::fromBase64(credHash);
req.setRawHeader(QByteArray("Cookie"), _cred->_token.toLocal8Bit());
return MirallAccessManager::createRequest(op, req, outgoingData);
}
private:
@@ -121,7 +112,7 @@ void TokenCredentials::syncContextPreInit (CSYNC* ctx)
void TokenCredentials::syncContextPreStart (CSYNC* ctx)
{
csync_set_module_property(ctx, "session_key", _token.toUtf8().data());
csync_set_module_property(ctx, "session_key", _token.toLocal8Bit().data());
}
bool TokenCredentials::changed(AbstractCredentials* credentials) const
@@ -165,6 +156,12 @@ bool TokenCredentials::ready() const
return _ready;
}
QString TokenCredentials::fetchUser(Account* account)
{
_user = account->credentialSetting(QLatin1String(userC)).toString();
return _user;
}
void TokenCredentials::fetch(Account *account)
{
if( !account ) {
@@ -172,11 +169,10 @@ void TokenCredentials::fetch(Account *account)
}
Q_EMIT fetched();
}
bool TokenCredentials::stillValid(QNetworkReply *reply)
{
return ((reply->error() != QNetworkReply::AuthenticationRequiredError)
// returned if user/password or token are incorrect
// returned if user or password is incorrect
&& (reply->error() != QNetworkReply::OperationCanceledError
|| !reply->property(authenticationFailedC).toBool()));
}
@@ -188,12 +184,19 @@ QString TokenCredentials::queryPassword(bool *ok)
void TokenCredentials::invalidateToken(Account *account)
{
qDebug() << Q_FUNC_INFO;
_ready = false;
account->clearCookieJar();
_token = QString();
_user = QString();
_password = QString();
_ready = false;
// User must be fetched from config file to generate a valid key
fetchUser(account);
const QString kck = keychainKey(account->url().toString(), _user);
if( kck.isEmpty() ) {
qDebug() << "InvalidateToken: User is empty, bailing out!";
return;
}
account->clearCookieJar();
}
void TokenCredentials::persist(Account *account)
+2 -1
Ver Arquivo
@@ -53,6 +53,7 @@ public:
QString password() const;
QString queryPassword(bool *ok);
void invalidateToken(Account *account);
QString fetchUser(Account *account);
private Q_SLOTS:
void slotAuthentication(QNetworkReply*, QAuthenticator*);
@@ -60,7 +61,7 @@ private Q_SLOTS:
private:
QString _user;
QString _password;
QString _token; // the cookies
QString _token;
bool _ready;
};
+1 -1
Ver Arquivo
@@ -71,7 +71,7 @@ QString applicationTrPath()
#elif defined(Q_OS_MAC)
return QApplication::applicationDirPath()+QLatin1String("/../Resources/Translations"); // path defaults to app dir.
#elif defined(Q_OS_UNIX)
return QString::fromLatin1(DATADIR "/" APPLICATION_EXECUTABLE "/i18n/");
return QString::fromLatin1(DATADIR"/"APPLICATION_EXECUTABLE"/i18n/");
#endif
}
}
-408
Ver Arquivo
@@ -1,408 +0,0 @@
/*
* Copyright (C) by Markus Goetz <markus@woboq.com>
*
* 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.
*/
#include "owncloudpropagator.h"
#include "propagator_qnam.h"
#include "propagatorjobs.h"
#include "propagator_legacy.h"
#include "mirall/utility.h"
#ifdef Q_OS_WIN
#include <windef.h>
#include <winbase.h>
#endif
#include <QTimer>
#include <QObject>
namespace Mirall {
// Because of the many layers of buffering inside Qt (and probably the OS and the network)
// we cannot lower this value much more. If we do, the estimated bw will be very high
// because the buffers fill fast while the actual network algorithms are not relevant yet.
static qint64 relativeLimitMeasuringTimerIntervalMsec = 1000*2;
// See also WritingState in http://code.woboq.org/qt5/qtbase/src/network/access/qhttpprotocolhandler.cpp.html#_ZN20QHttpProtocolHandler11sendRequestEv
// FIXME At some point:
// * Register device only after the QNR received its metaDataChanged() signal
// * Incorporate Qt buffer fill state (it's a negative absolute delta).
// * Incorporate SSL overhead (percentage)
// * For relative limiting, do less measuring and more delaying+giving quota
// * For relative limiting, smoothen measurements
BandwidthManager::BandwidthManager(OwncloudPropagator *p) : QObject(),
_propagator(p),
_relativeLimitCurrentMeasuredDevice(0),
_relativeUploadLimitProgressAtMeasuringRestart(0),
_currentUploadLimit(0),
_relativeLimitCurrentMeasuredJob(0),
_currentDownloadLimit(0)
{
_currentUploadLimit = _propagator->_uploadLimit.fetchAndAddAcquire(0);
_currentDownloadLimit = _propagator->_downloadLimit.fetchAndAddAcquire(0);
QObject::connect(&_switchingTimer, SIGNAL(timeout()), this, SLOT(switchingTimerExpired()));
_switchingTimer.setInterval(10*1000);
_switchingTimer.start();
QMetaObject::invokeMethod(this, "switchingTimerExpired", Qt::QueuedConnection);
// absolute uploads/downloads
QObject::connect(&_absoluteLimitTimer, SIGNAL(timeout()), this, SLOT(absoluteLimitTimerExpired()));
_absoluteLimitTimer.setInterval(1000);
_absoluteLimitTimer.start();
// Relative uploads
QObject::connect(&_relativeUploadMeasuringTimer,SIGNAL(timeout()),
this, SLOT(relativeUploadMeasuringTimerExpired()));
_relativeUploadMeasuringTimer.setInterval(relativeLimitMeasuringTimerIntervalMsec);
_relativeUploadMeasuringTimer.start();
_relativeUploadMeasuringTimer.setSingleShot(true); // will be restarted from the delay timer
QObject::connect(&_relativeUploadDelayTimer, SIGNAL(timeout()),
this, SLOT(relativeUploadDelayTimerExpired()));
_relativeUploadDelayTimer.setSingleShot(true); // will be restarted from the measuring timer
// Relative downloads
QObject::connect(&_relativeDownloadMeasuringTimer,SIGNAL(timeout()),
this, SLOT(relativeDownloadMeasuringTimerExpired()));
_relativeDownloadMeasuringTimer.setInterval(relativeLimitMeasuringTimerIntervalMsec);
_relativeDownloadMeasuringTimer.start();
_relativeDownloadMeasuringTimer.setSingleShot(true); // will be restarted from the delay timer
QObject::connect(&_relativeDownloadDelayTimer, SIGNAL(timeout()),
this, SLOT(relativeDownloadDelayTimerExpired()));
_relativeDownloadDelayTimer.setSingleShot(true); // will be restarted from the measuring timer
}
void BandwidthManager::registerUploadDevice(UploadDevice *p)
{
qDebug() << Q_FUNC_INFO << p;
_absoluteUploadDeviceList.append(p);
_relativeUploadDeviceList.append(p);
QObject::connect(p, SIGNAL(destroyed(QObject*)), this, SLOT(unregisterUploadDevice(QObject*)));
if (usingAbsoluteUploadLimit()) {
p->setBandwidthLimited(true);
p->setChoked(false);
} else if (usingRelativeUploadLimit()) {
p->setBandwidthLimited(true);
p->setChoked(true);
} else {
p->setBandwidthLimited(false);
p->setChoked(false);
}
}
void BandwidthManager::unregisterUploadDevice(QObject *o)
{
UploadDevice *p = qobject_cast<UploadDevice*>(o);
if (p) {
unregisterUploadDevice(p);
}
}
void BandwidthManager::unregisterUploadDevice(UploadDevice* p)
{
qDebug() << Q_FUNC_INFO << p;
_absoluteUploadDeviceList.removeAll(p);
_relativeUploadDeviceList.removeAll(p);
if (p == _relativeLimitCurrentMeasuredDevice) {
_relativeLimitCurrentMeasuredDevice = 0;
_relativeUploadLimitProgressAtMeasuringRestart = 0;
}
}
void BandwidthManager::registerDownloadJob(GETFileJob* j)
{
qDebug() << Q_FUNC_INFO << j;
_downloadJobList.append(j);
QObject::connect(j, SIGNAL(destroyed(QObject*)), this, SLOT(unregisterDownloadJob(QObject*)));
if (usingAbsoluteDownloadLimit()) {
j->setBandwidthLimited(true);
j->setChoked(false);
} else if (usingRelativeDownloadLimit()) {
j->setBandwidthLimited(true);
j->setChoked(true);
} else {
j->setBandwidthLimited(false);
j->setChoked(false);
}
}
void BandwidthManager::unregisterDownloadJob(GETFileJob* j)
{
_downloadJobList.removeAll(j);
if (_relativeLimitCurrentMeasuredJob == j) {
_relativeLimitCurrentMeasuredJob = 0;
_relativeDownloadLimitProgressAtMeasuringRestart = 0;
}
}
void BandwidthManager::unregisterDownloadJob(QObject* o)
{
GETFileJob *p = qobject_cast<GETFileJob*>(o);
if (p) {
unregisterDownloadJob(p);
}
}
void BandwidthManager::relativeUploadMeasuringTimerExpired()
{
if (!usingRelativeUploadLimit() || _relativeUploadDeviceList.count() == 0) {
// Not in this limiting mode, just wait 1 sec to continue the cycle
_relativeUploadDelayTimer.setInterval(1000);
_relativeUploadDelayTimer.start();
return;
}
if (_relativeLimitCurrentMeasuredDevice == 0) {
qDebug() << Q_FUNC_INFO << "No device set, just waiting 1 sec";
_relativeUploadDelayTimer.setInterval(1000);
_relativeUploadDelayTimer.start();
return;
}
qDebug() << Q_FUNC_INFO << _relativeUploadDeviceList.count() << "Starting Delay";
qint64 relativeLimitProgressMeasured = (_relativeLimitCurrentMeasuredDevice->_readWithProgress
+ _relativeLimitCurrentMeasuredDevice->_read) / 2;
qint64 relativeLimitProgressDifference = relativeLimitProgressMeasured - _relativeUploadLimitProgressAtMeasuringRestart;
qDebug() << Q_FUNC_INFO << _relativeUploadLimitProgressAtMeasuringRestart
<< relativeLimitProgressMeasured << relativeLimitProgressDifference;
qint64 speedkBPerSec = (relativeLimitProgressDifference / relativeLimitMeasuringTimerIntervalMsec*1000.0) / 1024.0;
qDebug() << Q_FUNC_INFO << relativeLimitProgressDifference/1024 <<"kB =>" << speedkBPerSec << "kB/sec on full speed ("
<< _relativeLimitCurrentMeasuredDevice->_readWithProgress << _relativeLimitCurrentMeasuredDevice->_read
<< qAbs(_relativeLimitCurrentMeasuredDevice->_readWithProgress
- _relativeLimitCurrentMeasuredDevice->_read) << ")";
qint64 uploadLimitPercent = -_currentUploadLimit;
// don't use too extreme values
uploadLimitPercent = qMin(uploadLimitPercent, qint64(90));
uploadLimitPercent = qMax(qint64(10), uploadLimitPercent);
qint64 wholeTimeMsec = (100.0 / uploadLimitPercent) * relativeLimitMeasuringTimerIntervalMsec;
qint64 waitTimeMsec = wholeTimeMsec - relativeLimitMeasuringTimerIntervalMsec;
qint64 realWaitTimeMsec = waitTimeMsec + wholeTimeMsec;
qDebug() << Q_FUNC_INFO << waitTimeMsec << " - "<< realWaitTimeMsec <<
" msec for " << uploadLimitPercent << "%";
qDebug() << Q_FUNC_INFO << "XXXX" << uploadLimitPercent << relativeLimitMeasuringTimerIntervalMsec;
// We want to wait twice as long since we want to give all
// devices the same quota we used now since we don't want
// any upload to timeout
_relativeUploadDelayTimer.setInterval(realWaitTimeMsec);
_relativeUploadDelayTimer.start();
int deviceCount = _relativeUploadDeviceList.count();
qint64 quotaPerDevice = relativeLimitProgressDifference * (uploadLimitPercent / 100.0) / deviceCount + 1.0;
qDebug() << Q_FUNC_INFO << "YYYY" << relativeLimitProgressDifference << uploadLimitPercent << deviceCount;
Q_FOREACH(UploadDevice *ud, _relativeUploadDeviceList) {
ud->setBandwidthLimited(true);
ud->setChoked(false);
ud->giveBandwidthQuota(quotaPerDevice);
qDebug() << Q_FUNC_INFO << "Gave" << quotaPerDevice/1024.0 << "kB to" << ud;
}
_relativeLimitCurrentMeasuredDevice = 0;
}
void BandwidthManager::relativeUploadDelayTimerExpired()
{
// Switch to measuring state
_relativeUploadMeasuringTimer.start(); // always start to continue the cycle
if (!usingRelativeUploadLimit()) {
return; // oh, not actually needed
}
if (_relativeUploadDeviceList.isEmpty()) {
return;
}
qDebug() << Q_FUNC_INFO << _relativeUploadDeviceList.count() << "Starting measuring";
// Take first device and then append it again (= we round robin all devices)
_relativeLimitCurrentMeasuredDevice = _relativeUploadDeviceList.takeFirst();
_relativeUploadDeviceList.append(_relativeLimitCurrentMeasuredDevice);
_relativeUploadLimitProgressAtMeasuringRestart = (_relativeLimitCurrentMeasuredDevice->_readWithProgress
+ _relativeLimitCurrentMeasuredDevice->_read) / 2;
_relativeLimitCurrentMeasuredDevice->setBandwidthLimited(false);
_relativeLimitCurrentMeasuredDevice->setChoked(false);
// choke all other UploadDevices
Q_FOREACH(UploadDevice *ud, _relativeUploadDeviceList) {
if (ud != _relativeLimitCurrentMeasuredDevice) {
ud->setBandwidthLimited(true);
ud->setChoked(true);
}
}
// now we're in measuring state
}
// for downloads:
void BandwidthManager::relativeDownloadMeasuringTimerExpired()
{
if (!usingRelativeDownloadLimit() || _downloadJobList.count() == 0) {
// Not in this limiting mode, just wait 1 sec to continue the cycle
_relativeDownloadDelayTimer.setInterval(1000);
_relativeDownloadDelayTimer.start();
return;
}
if (_relativeLimitCurrentMeasuredJob == 0) {
qDebug() << Q_FUNC_INFO << "No job set, just waiting 1 sec";
_relativeDownloadDelayTimer.setInterval(1000);
_relativeDownloadDelayTimer.start();
return;
}
qDebug() << Q_FUNC_INFO << _downloadJobList.count() << "Starting Delay";
qint64 relativeLimitProgressMeasured = _relativeLimitCurrentMeasuredJob->currentDownloadPosition();
qint64 relativeLimitProgressDifference = relativeLimitProgressMeasured - _relativeDownloadLimitProgressAtMeasuringRestart;
qDebug() << Q_FUNC_INFO << _relativeDownloadLimitProgressAtMeasuringRestart
<< relativeLimitProgressMeasured << relativeLimitProgressDifference;
qint64 speedkBPerSec = (relativeLimitProgressDifference / relativeLimitMeasuringTimerIntervalMsec*1000.0) / 1024.0;
qDebug() << Q_FUNC_INFO << relativeLimitProgressDifference/1024 <<"kB =>" << speedkBPerSec << "kB/sec on full speed ("
<< _relativeLimitCurrentMeasuredJob->currentDownloadPosition() ;
qint64 downloadLimitPercent = -_currentDownloadLimit;
// don't use too extreme values
downloadLimitPercent = qMin(downloadLimitPercent, qint64(90));
downloadLimitPercent = qMax(qint64(10), downloadLimitPercent);
qint64 wholeTimeMsec = (100.0 / downloadLimitPercent) * relativeLimitMeasuringTimerIntervalMsec;
qint64 waitTimeMsec = wholeTimeMsec - relativeLimitMeasuringTimerIntervalMsec;
qint64 realWaitTimeMsec = waitTimeMsec + wholeTimeMsec;
qDebug() << Q_FUNC_INFO << waitTimeMsec << " - "<< realWaitTimeMsec <<
" msec for " << downloadLimitPercent << "%";
qDebug() << Q_FUNC_INFO << "XXXX" << downloadLimitPercent << relativeLimitMeasuringTimerIntervalMsec;
// We want to wait twice as long since we want to give all
// devices the same quota we used now since we don't want
// any upload to timeout
_relativeDownloadDelayTimer.setInterval(realWaitTimeMsec);
_relativeDownloadDelayTimer.start();
int jobCount = _downloadJobList.count();
qint64 quota = relativeLimitProgressDifference * (downloadLimitPercent / 100.0);
// if (quota > 20*1024) {
// qDebug() << "======== ADJUSTING QUOTA FROM " << quota << " TO " << quota - 20*1024;
// quota -= 20*1024;
// }
qint64 quotaPerJob = quota / jobCount + 1.0;
qDebug() << Q_FUNC_INFO << "YYYY" << relativeLimitProgressDifference << downloadLimitPercent << jobCount;
Q_FOREACH(GETFileJob *gfj, _downloadJobList) {
gfj->setBandwidthLimited(true);
gfj->setChoked(false);
gfj->giveBandwidthQuota(quotaPerJob);
qDebug() << Q_FUNC_INFO << "Gave" << quotaPerJob/1024.0 << "kB to" << gfj;
}
_relativeLimitCurrentMeasuredDevice = 0;
}
void BandwidthManager::relativeDownloadDelayTimerExpired()
{
// Switch to measuring state
_relativeDownloadMeasuringTimer.start(); // always start to continue the cycle
if (!usingRelativeDownloadLimit()) {
return; // oh, not actually needed
}
if (_downloadJobList.isEmpty()) {
//qDebug() << Q_FUNC_INFO << _downloadJobList.count() << "No jobs?";
return;
}
qDebug() << Q_FUNC_INFO << _downloadJobList.count() << "Starting measuring";
// Take first device and then append it again (= we round robin all devices)
_relativeLimitCurrentMeasuredJob = _downloadJobList.takeFirst();
_downloadJobList.append(_relativeLimitCurrentMeasuredJob);
_relativeDownloadLimitProgressAtMeasuringRestart = _relativeLimitCurrentMeasuredJob->currentDownloadPosition();
_relativeLimitCurrentMeasuredJob->setBandwidthLimited(false);
_relativeLimitCurrentMeasuredJob->setChoked(false);
// choke all other UploadDevices
Q_FOREACH(GETFileJob *gfj, _downloadJobList) {
if (gfj != _relativeLimitCurrentMeasuredJob) {
gfj->setBandwidthLimited(true);
gfj->setChoked(true);
}
}
// now we're in measuring state
}
// end downloads
void BandwidthManager::switchingTimerExpired() {
qint64 newUploadLimit = _propagator->_uploadLimit.fetchAndAddAcquire(0);
if (newUploadLimit != _currentUploadLimit) {
qDebug() << Q_FUNC_INFO << "Upload Bandwidth limit changed" << _currentUploadLimit << newUploadLimit;
_currentUploadLimit = newUploadLimit;
Q_FOREACH(UploadDevice *ud, _relativeUploadDeviceList) {
if (newUploadLimit == 0) {
ud->setBandwidthLimited(false);
ud->setChoked(false);
} else if (newUploadLimit > 0) {
ud->setBandwidthLimited(true);
ud->setChoked(false);
} else if (newUploadLimit < 0) {
ud->setBandwidthLimited(true);
ud->setChoked(true);
}
}
}
qint64 newDownloadLimit = _propagator->_downloadLimit.fetchAndAddAcquire(0);
if (newDownloadLimit != _currentDownloadLimit) {
qDebug() << Q_FUNC_INFO << "Download Bandwidth limit changed" << _currentDownloadLimit << newDownloadLimit;
_currentDownloadLimit = newDownloadLimit;
Q_FOREACH(GETFileJob *j, _downloadJobList) {
if (usingAbsoluteDownloadLimit()) {
j->setBandwidthLimited(true);
j->setChoked(false);
} else if (usingRelativeDownloadLimit()) {
j->setBandwidthLimited(true);
j->setChoked(true);
} else {
j->setBandwidthLimited(false);
j->setChoked(false);
}
}
}
}
void BandwidthManager::absoluteLimitTimerExpired()
{
if (usingAbsoluteUploadLimit() && _absoluteUploadDeviceList.count() > 0) {
qint64 quotaPerDevice = _currentUploadLimit / qMax(1, _absoluteUploadDeviceList.count());
qDebug() << Q_FUNC_INFO << quotaPerDevice << _absoluteUploadDeviceList.count() << _currentUploadLimit;
Q_FOREACH(UploadDevice *device, _absoluteUploadDeviceList) {
device->giveBandwidthQuota(quotaPerDevice);
qDebug() << Q_FUNC_INFO << "Gave " << quotaPerDevice/1024.0 << " kB to" << device;
}
}
if (usingAbsoluteDownloadLimit() && _downloadJobList.count() > 0) {
qint64 quotaPerJob = _currentDownloadLimit / qMax(1, _downloadJobList.count());
qDebug() << Q_FUNC_INFO << quotaPerJob << _downloadJobList.count() << _currentDownloadLimit;
Q_FOREACH(GETFileJob *j, _downloadJobList) {
j->giveBandwidthQuota(quotaPerJob);
qDebug() << Q_FUNC_INFO << "Gave " << quotaPerJob/1024.0 << " kB to" << j;
}
}
}
}
-83
Ver Arquivo
@@ -1,83 +0,0 @@
/*
* Copyright (C) by Markus Goetz <markus@woboq.com>
*
* 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.
*/
#ifndef BANDWIDTHMANAGER_H
#define BANDWIDTHMANAGER_H
#include <QObject>
#include <QLinkedList>
#include <QTimer>
#include <QIODevice>
namespace Mirall {
class UploadDevice;
class GETFileJob;
class OwncloudPropagator;
class BandwidthManager : public QObject {
Q_OBJECT
public:
BandwidthManager(OwncloudPropagator *p);
bool usingAbsoluteUploadLimit() { return _currentUploadLimit > 0; }
bool usingRelativeUploadLimit() { return _currentUploadLimit < 0; }
bool usingAbsoluteDownloadLimit() { return _currentDownloadLimit > 0; }
bool usingRelativeDownloadLimit() { return _currentDownloadLimit < 0; }
public slots:
void registerUploadDevice(UploadDevice*);
void unregisterUploadDevice(UploadDevice*);
void unregisterUploadDevice(QObject*);
void registerDownloadJob(GETFileJob*);
void unregisterDownloadJob(GETFileJob*);
void unregisterDownloadJob(QObject*);
void absoluteLimitTimerExpired();
void switchingTimerExpired();
void relativeUploadMeasuringTimerExpired();
void relativeUploadDelayTimerExpired();
void relativeDownloadMeasuringTimerExpired();
void relativeDownloadDelayTimerExpired();
private:
QTimer _switchingTimer; // for switching between absolute and relative bw limiting
OwncloudPropagator *_propagator; // FIXME this timer and this variable should be replaced
// by the propagator emitting the changed limit values to us as signal
QTimer _absoluteLimitTimer; // for absolute up/down bw limiting
QLinkedList<UploadDevice*> _absoluteUploadDeviceList;
QLinkedList<UploadDevice*> _relativeUploadDeviceList; // FIXME merge with list above ^^
QTimer _relativeUploadMeasuringTimer;
QTimer _relativeUploadDelayTimer; // for relative bw limiting, we need to wait this amount before measuring again
UploadDevice *_relativeLimitCurrentMeasuredDevice; // the device measured
qint64 _relativeUploadLimitProgressAtMeasuringRestart; // for measuring how much progress we made at start
qint64 _currentUploadLimit;
QLinkedList<GETFileJob*> _downloadJobList;
QTimer _relativeDownloadMeasuringTimer;
QTimer _relativeDownloadDelayTimer; // for relative bw limiting, we need to wait this amount before measuring again
GETFileJob *_relativeLimitCurrentMeasuredJob; // the device measured
qint64 _relativeDownloadLimitProgressAtMeasuringRestart; // for measuring how much progress we made at start
qint64 _currentDownloadLimit;
};
}
#endif
+20 -89
Ver Arquivo
@@ -122,7 +122,9 @@ bool Folder::init()
csync_set_log_level( 11 );
MirallConfigFile cfgFile;
csync_set_config_dir( _csync_ctx, cfgFile.configPath().toUtf8() );
setIgnoredFiles();
if (Account *account = AccountManager::instance()->account()) {
account->credentials()->syncContextPreInit(_csync_ctx);
} else {
@@ -266,7 +268,6 @@ void Folder::slotPollTimerTimeout()
qDebug() << "* Polling" << alias() << "for changes. (time since last sync:" << (_timeSinceLastSync.elapsed() / 1000) << "s)";
if (quint64(_timeSinceLastSync.elapsed()) > MirallConfigFile().forceSyncInterval() ||
_lastEtag.isNull() ||
!(_syncResult.status() == SyncResult::Success ||_syncResult.status() == SyncResult::Problem)) {
qDebug() << "** Force Sync now, state is " << _syncResult.statusString();
emit scheduleToSync(alias());
@@ -605,8 +606,6 @@ void Folder::startSync(const QStringList &pathList)
SLOT(slotAboutToRemoveAllFiles(SyncFileItem::Direction,bool*)));
connect(_engine.data(), SIGNAL(transmissionProgress(Progress::Info)), this, SLOT(slotTransmissionProgress(Progress::Info)));
setDirtyNetworkLimits();
QMetaObject::invokeMethod(_engine.data(), "startSync", Qt::QueuedConnection);
// disable events until syncing is done
@@ -618,21 +617,7 @@ void Folder::startSync(const QStringList &pathList)
void Folder::setDirtyNetworkLimits()
{
if (_engine) {
MirallConfigFile cfg;
int downloadLimit = 0;
if (cfg.useDownloadLimit()) {
downloadLimit = cfg.downloadLimit() * 1000;
}
int uploadLimit = -75; // 75%
int useUpLimit = cfg.useUploadLimit();
if ( useUpLimit >= 1) {
uploadLimit = cfg.uploadLimit() * 1000;
} else if (useUpLimit == 0) {
uploadLimit = 0;
}
_engine->setNetworkLimits(uploadLimit, downloadLimit);
_engine->setNetworkLimits();
}
}
@@ -660,13 +645,10 @@ void Folder::slotSyncFinished()
bubbleUpSyncResult();
bool anotherSyncNeeded = false;
if (_engine) {
anotherSyncNeeded = _engine->isAnotherSyncNeeded();
_engine.reset(0);
}
_engine.reset(0);
// _watcher->setEventsEnabledDelayed(2000);
_pollTimer.start();
_timeSinceLastSync.restart();
if (_csyncError) {
@@ -693,16 +675,6 @@ void Folder::slotSyncFinished()
// all come in.
QTimer::singleShot(200, this, SLOT(slotEmitFinishedDelayed() ));
if (!anotherSyncNeeded) {
_pollTimer.start();
_timeSinceLastSync.restart();
} else {
// Another sync is required. We will make sure that the poll timer occurs soon enough
// and we clear the etag to force a sync
_lastEtag.clear();
QTimer::singleShot(1000, this, SLOT(slotPollTimerTimeout() ));
}
}
void Folder::slotEmitFinishedDelayed()
@@ -755,38 +727,6 @@ void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *
#endif
}
// compute the file status of a directory recursively. It returns either
// "all in sync" or "needs update" or "error", no more details.
SyncFileStatus Folder::recursiveFolderStatus( const QString& fileName )
{
QDir dir(path() + fileName);
const QStringList dirEntries = dir.entryList( QDir::AllEntries | QDir::NoDotAndDotDot );
foreach( const QString entry, dirEntries ) {
QFileInfo fi(entry);
SyncFileStatus sfs;
if( fi.isDir() ) {
sfs = recursiveFolderStatus( fileName + QLatin1Char('/') + entry );
} else {
QString fs( fileName + QLatin1Char('/') + entry );
if( fileName.isEmpty() ) {
// toplevel, no slash etc. needed.
fs = entry;
}
sfs = fileStatus( fs );
}
if( sfs == FILE_STATUS_STAT_ERROR || sfs == FILE_STATUS_ERROR ) {
return FILE_STATUS_ERROR;
}
if( sfs != FILE_STATUS_SYNC) {
return FILE_STATUS_EVAL;
}
}
return FILE_STATUS_SYNC;
}
SyncFileStatus Folder::fileStatus( const QString& fileName )
{
/*
@@ -806,11 +746,7 @@ SyncFileStatus Folder::fileStatus( const QString& fileName )
// FIXME: Find a way for STATUS_ERROR
SyncFileStatus stat = FILE_STATUS_NONE;
QString file = fileName;
if( path() != QLatin1String("/") ) {
file = path() + fileName;
}
QString file = path() + fileName;
QFileInfo fi(file);
if( !fi.exists() ) {
@@ -834,25 +770,20 @@ SyncFileStatus Folder::fileStatus( const QString& fileName )
}
}
if( type == CSYNC_FTW_TYPE_DIR ) {
// compute recursive status of the directory
stat = recursiveFolderStatus( fileName );
} else {
if( stat == FILE_STATUS_NONE ) {
SyncJournalFileRecord rec = _journal.getFileRecord(fileName);
if( !rec.isValid() ) {
stat = FILE_STATUS_NEW;
}
// file was locally modified.
if( stat == FILE_STATUS_NONE && fi.lastModified() != rec._modtime ) {
stat = FILE_STATUS_EVAL;
}
}
if( stat == FILE_STATUS_NONE ) {
stat = FILE_STATUS_SYNC;
}
SyncJournalFileRecord rec = _journal.getFileRecord(fileName);
if( stat == FILE_STATUS_NONE && !rec.isValid() ) {
stat = FILE_STATUS_NEW;
}
// file was locally modified.
if( stat == FILE_STATUS_NONE && fi.lastModified() != rec._modtime ) {
stat = FILE_STATUS_EVAL;
}
if( stat == FILE_STATUS_NONE ) {
stat = FILE_STATUS_SYNC;
}
return stat;
}
+1 -11
Ver Arquivo
@@ -76,17 +76,6 @@ public:
*/
SyncFileStatus fileStatus( const QString& );
/**
* @brief recursiveFolderStatus
* @param fileName - the relative file name to examine
* @return the resulting status
*
* The resulting status can only be either SYNC which means all files
* are in sync, ERROR if an error occured, or EVAL if something needs
* to be synced underneath this dir.
*/
SyncFileStatus recursiveFolderStatus( const QString& fileName );
/**
* alias or nickname
*/
@@ -197,6 +186,7 @@ private slots:
private:
bool init();
void setIgnoredFiles();
void bubbleUpSyncResult();
-20
Ver Arquivo
@@ -15,8 +15,6 @@
#include <QNetworkProxy>
#include <QAuthenticator>
#include <QSslConfiguration>
#include <QNetworkCookie>
#include <QNetworkCookieJar>
#include "mirall/cookiejar.h"
#include "mirall/mirallaccessmanager.h"
@@ -39,27 +37,9 @@ MirallAccessManager::MirallAccessManager(QObject* parent)
this, SLOT(slotProxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
}
void MirallAccessManager::setRawCookie(const QByteArray &rawCookie, const QUrl &url)
{
QNetworkCookie cookie(rawCookie.left(rawCookie.indexOf('=')),
rawCookie.mid(rawCookie.indexOf('=')+1));
qDebug() << Q_FUNC_INFO << cookie.name() << cookie.value();
QList<QNetworkCookie> cookieList;
cookieList.append(cookie);
QNetworkCookieJar *jar = cookieJar();
jar->setCookiesFromUrl(cookieList, url);
}
QNetworkReply* MirallAccessManager::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& request, QIODevice* outgoingData)
{
QNetworkRequest newRequest(request);
if (newRequest.hasRawHeader("cookie")) {
// This will set the cookie into the QNetworkCookieJar which will then override the cookie header
setRawCookie(request.rawHeader("cookie"), request.url());
}
newRequest.setRawHeader(QByteArray("User-Agent"), Utility::userAgentString());
QByteArray verb = newRequest.attribute(QNetworkRequest::CustomVerbAttribute).toByteArray();
// For PROPFIND (assumed to be a WebDAV op), set xml/utf8 as content type/encoding
-4
Ver Arquivo
@@ -17,8 +17,6 @@
#include "owncloudlib.h"
#include <QNetworkAccessManager>
class QByteArray;
class QUrl;
namespace Mirall
{
@@ -29,8 +27,6 @@ class OWNCLOUDSYNC_EXPORT MirallAccessManager : public QNetworkAccessManager
public:
MirallAccessManager(QObject* parent = 0);
void setRawCookie(const QByteArray &rawCookie, const QUrl &url);
protected:
QNetworkReply* createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& request, QIODevice* outgoingData = 0);
protected slots:
+1 -2
Ver Arquivo
@@ -31,7 +31,6 @@
#include "mirall/networkjobs.h"
#include "mirall/account.h"
#include "mirall/owncloudpropagator.h"
#include "creds/credentialsfactory.h"
#include "creds/abstractcredentials.h"
@@ -49,7 +48,7 @@ AbstractNetworkJob::AbstractNetworkJob(Account *account, const QString &path, QO
, _path(path)
{
_timer.setSingleShot(true);
_timer.setInterval(OwncloudPropagator::httpTimeout() * 1000); // default to 5 minutes.
_timer.setInterval(10*1000); // default to 10 seconds.
connect(&_timer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
}
+16 -90
Ver Arquivo
@@ -21,7 +21,6 @@
#include "propagator_legacy.h"
#include "mirall/mirallconfigfile.h"
#include "mirall/utility.h"
#include <json.h>
#ifdef Q_OS_WIN
#include <windef.h>
@@ -30,15 +29,11 @@
#include <QStack>
#include <QFileInfo>
#include <QTimer>
#include <QObject>
#include <QTimerEvent>
namespace Mirall {
/* The maximum number of active job in parallel */
int OwncloudPropagator::maximumActiveJob()
{
static int maximumActiveJob() {
static int max = qgetenv("OWNCLOUD_MAX_PARALLEL").toUInt();
if (!max) {
max = 3; //default
@@ -46,18 +41,9 @@ int OwncloudPropagator::maximumActiveJob()
return max;
}
void PropagateItemJob::done(SyncFileItem::Status status, const QString &errorString)
{
if (_item._isRestoration) {
if( status == SyncFileItem::Success || status == SyncFileItem::Conflict) {
status = SyncFileItem::Restoration;
} else {
_item._errorString += tr("; Restoration Failed: ") + errorString;
}
} else {
_item._errorString = errorString;
}
_item._errorString = errorString;
_item._status = status;
// Blacklisting
@@ -91,7 +77,6 @@ void PropagateItemJob::done(SyncFileItem::Status status, const QString &errorStr
_propagator->_journal->updateBlacklistEntry( record );
break;
case SyncFileItem::Success:
case SyncFileItem::Restoration:
if( _item._blacklistedInDb ) {
// wipe blacklist entry.
_propagator->_journal->wipeBlacklistEntry(_item._file);
@@ -147,7 +132,6 @@ bool PropagateItemJob::checkForProblemsWithShared(int httpStatusCode, const QStr
// Also remove the inodes and fileid from the db so no further renames are tried for
// this item.
_propagator->_journal->avoidRenamesOnNextSync(_item._file);
_propagator->_anotherSyncNeeded = true;
}
if( newJob ) {
newJob->setRestoreJobMsg(msg);
@@ -169,8 +153,7 @@ void PropagateItemJob::slotRestoreJobCompleted(const SyncFileItem& item )
_restoreJob->setRestoreJobMsg();
}
if( item._status == SyncFileItem::Success || item._status == SyncFileItem::Conflict
|| item._status == SyncFileItem::Restoration) {
if( item._status == SyncFileItem::Success || item._status == SyncFileItem::Conflict) {
done( SyncFileItem::SoftError, msg);
} else {
done( item._status, tr("A file or directory was removed from a read only share, but restoring failed: %1").arg(item._errorString) );
@@ -215,7 +198,6 @@ PropagateItemJob* OwncloudPropagator::createJob(const SyncFileItem& item) {
return new PropagateLocalRename(this, item);
}
case CSYNC_INSTRUCTION_IGNORE:
case CSYNC_INSTRUCTION_ERROR:
return new PropagateIgnoreJob(this, item);
default:
return 0;
@@ -223,13 +205,14 @@ PropagateItemJob* OwncloudPropagator::createJob(const SyncFileItem& item) {
return 0;
}
void OwncloudPropagator::start(const SyncFileItemVector& items)
void OwncloudPropagator::start(const SyncFileItemVector& _syncedItems)
{
/* This builds all the job needed for the propagation.
* Each directories is a PropagateDirectory job, which contains the files in it.
* In order to do that we loop over the items. (which are sorted by destination)
* When we enter adirectory, we can create the directory job and push it on the stack. */
* In order to do that we sort the items by destination. and loop over it. When we enter a
* directory, we can create the directory job and push it on the stack. */
SyncFileItemVector items = _syncedItems;
std::sort(items.begin(), items.end());
_rootJob.reset(new PropagateDirectory(this));
QStack<QPair<QString /* directory name */, PropagateDirectory* /* job */> > directories;
directories.push(qMakePair(QString(), _rootJob.data()));
@@ -320,31 +303,14 @@ bool OwncloudPropagator::isInSharedDirectory(const QString& file)
*/
bool OwncloudPropagator::useLegacyJobs()
{
if (_downloadLimit.fetchAndAddAcquire(0) != 0 || _uploadLimit.fetchAndAddAcquire(0) != 0) {
// QNAM does not support bandwith limiting
return true;
}
// Allow an environement variable for debugging
QByteArray env = qgetenv("OWNCLOUD_USE_LEGACY_JOBS");
if (env=="true" || env =="1") {
qDebug() << "Force Legacy Propagator ACTIVATED";
return true;
}
env = qgetenv("OWNCLOUD_NEW_BANDWIDTH_LIMITING");
if (env=="true" || env =="1") {
qDebug() << "New Bandwidth Limiting Code ACTIVATED";
// Only certain Qt versions support this at the moment.
// They need those Change-Ids: Idb1c2d5a382a704d8cc08fe03c55c883bfc95aa7 Iefbcb1a21d8aedef1eb11761232dd16a049018dc
// FIXME We need to check the Qt version and then also return false here as soon
// as mirall ships with those Qt versions on Windows and OS X
return false;
}
if (_downloadLimit.fetchAndAddAcquire(0) != 0 || _uploadLimit.fetchAndAddAcquire(0) != 0) {
qDebug() << "Switching To Legacy Propagator Because Of Bandwidth Limit ACTIVATED";
// QNAM does not support bandwith limiting
// in most Qt versions.
return true;
}
return false;
return env=="true" || env =="1";
}
int OwncloudPropagator::httpTimeout()
@@ -420,8 +386,7 @@ void PropagateDirectory::start()
void PropagateDirectory::slotSubJobFinished(SyncFileItem::Status status)
{
if (status == SyncFileItem::FatalError ||
(_current == -1 && status != SyncFileItem::Success && status != SyncFileItem::Restoration)) {
if (status == SyncFileItem::FatalError || (_current == -1 && status != SyncFileItem::Success)) {
abort();
emit finished(status);
return;
@@ -438,7 +403,7 @@ void PropagateDirectory::slotSubJobReady()
return; // Ignore the case when the _fistJob is ready and not yet finished
if (_runningNow && _current >= 0 && _current < _subJobs.count()) {
// there is a job running and the current one is not ready yet, we can't start new job
if (!_subJobs[_current]->_readySent || _propagator->_activeJobs >= _propagator->maximumActiveJob())
if (!_subJobs[_current]->_readySent || _propagator->_activeJobs >= maximumActiveJob())
return;
}
@@ -457,12 +422,6 @@ void PropagateDirectory::slotSubJobReady()
}
if (_item._should_update_etag && _item._instruction != CSYNC_INSTRUCTION_REMOVE) {
if (PropagateRemoteMkdir* mkdir = qobject_cast<PropagateRemoteMkdir*>(_firstJob.data())) {
// special case from MKDIR, get the fileId from the job there
if (_item._fileId.isEmpty() && !mkdir->_item._fileId.isEmpty()) {
_item._fileId = mkdir->_item._fileId;
}
}
SyncJournalFileRecord record(_item, _propagator->_localDir + _item._file);
_propagator->_journal->setFileRecord(record);
}
@@ -471,37 +430,4 @@ void PropagateDirectory::slotSubJobReady()
}
}
void CleanupPollsJob::start()
{
if (_pollInfos.empty()) {
emit finished();
deleteLater();
return;
}
auto info = _pollInfos.takeFirst();
SyncFileItem item;
item._file = info._file;
item._modtime = info._modtime;
PollJob *job = new PollJob(_account, info._url, item, _journal, _localPath, this);
connect(job, SIGNAL(finishedSignal()), SLOT(slotPollFinished()));
job->start();
}
void CleanupPollsJob::slotPollFinished()
{
PollJob *job = qobject_cast<PollJob *>(sender());
Q_ASSERT(job);
if (job->_item._status == SyncFileItem::FatalError) {
emit aborted(job->_item._errorString);
return;
} else if (job->_item._status != SyncFileItem::Success) {
qDebug() << "There was an error with file " << job->_item._file << job->_item._errorString;
} else {
_journal->setFileRecord(SyncJournalFileRecord(job->_item, _localPath + job->_item._file));
}
// Continue with the next entry, or finish
start();
}
}
+8 -88
Ver Arquivo
@@ -18,26 +18,16 @@
#include <neon/ne_request.h>
#include <QHash>
#include <QObject>
#include <QMap>
#include <QLinkedList>
#include <QElapsedTimer>
#include <QTimer>
#include <QPointer>
#include <QIODevice>
#include <qelapsedtimer.h>
#include "syncfileitem.h"
#include "syncjournaldb.h"
#include "bandwidthmanager.h"
struct hbf_transfer_s;
struct ne_session_s;
struct ne_decompress_s;
typedef struct ne_prop_result_set_s ne_prop_result_set;
namespace Mirall {
class Account;
class SyncJournalDb;
class OwncloudPropagator;
@@ -46,8 +36,10 @@ class PropagatorJob : public QObject {
protected:
OwncloudPropagator *_propagator;
void emitReady() {
bool wasReady = _readySent;
_readySent = true;
emit ready();
if (!wasReady)
emit ready();
};
public:
bool _readySent;
@@ -147,15 +139,11 @@ protected:
* set a custom restore job message that is used if the restore job succeeded.
* It is displayed in the activity view.
*/
QString restoreJobMsg() const {
return _item._isRestoration ? _item._errorString : QString();
}
void setRestoreJobMsg( const QString& msg = QString() ) {
_item._isRestoration = true;
_item._errorString = msg;
}
QString restoreJobMsg() const { return _restoreJobMsg; }
void setRestoreJobMsg( const QString& msg = QString() ) { _restoreJobMsg = msg; }
SyncFileItem _item;
QString _restoreJobMsg;
protected slots:
void slotRestoreJobCompleted(const SyncFileItem& );
@@ -176,48 +164,10 @@ public:
PropagateIgnoreJob(OwncloudPropagator* propagator,const SyncFileItem& item)
: PropagateItemJob(propagator, item) {}
void start() {
SyncFileItem::Status status = _item._status;
done(status == SyncFileItem::NoStatus ? SyncFileItem::FileIgnored : status, _item._errorString);
done(SyncFileItem::FileIgnored, _item._errorString);
}
};
class BandwidthManager; // fwd
class UploadDevice : public QIODevice {
Q_OBJECT
public:
QPointer<QIODevice> _file;
qint64 _read;
qint64 _size;
qint64 _start;
QPointer<BandwidthManager> _bandwidthManager;
qint64 _bandwidthQuota;
qint64 _readWithProgress;
UploadDevice(QIODevice *file, qint64 start, qint64 size, BandwidthManager *bwm);
~UploadDevice();
virtual qint64 writeData(const char* , qint64 );
virtual qint64 readData(char* data, qint64 maxlen);
virtual bool atEnd() const;
virtual qint64 size() const;
qint64 bytesAvailable() const;
virtual bool isSequential() const;
virtual bool seek ( qint64 pos );
void setBandwidthLimited(bool);
bool isBandwidthLimited() { return _bandwidthLimited; }
void setChoked(bool);
bool isChoked() { return _choked; }
void giveBandwidthQuota(qint64 bwq);
private:
bool _bandwidthLimited; // if _bandwidthQuota will be used
bool _choked; // if upload is paused (readData() will return 0)
protected slots:
void slotJobUploadProgress(qint64 sent, qint64 t);
};
//Q_DECLARE_METATYPE(UploadDevice);
//Q_DECLARE_METATYPE(QPointer<UploadDevice>);
class OwncloudPropagator : public QObject {
Q_OBJECT
@@ -239,8 +189,6 @@ public:
SyncJournalDb * const _journal;
bool _finishedEmited; // used to ensure that finished is only emit once
BandwidthManager _bandwidthManager;
public:
OwncloudPropagator(ne_session_s *session, const QString &localDir, const QString &remoteDir, const QString &remoteFolder,
SyncJournalDb *progressDb, QThread *neonThread)
@@ -251,9 +199,7 @@ public:
, _remoteFolder((remoteFolder.endsWith(QChar('/'))) ? remoteFolder : remoteFolder+'/' )
, _journal(progressDb)
, _finishedEmited(false)
, _bandwidthManager(this)
, _activeJobs(0)
, _anotherSyncNeeded(false)
{ }
void start(const SyncFileItemVector &_syncedItems);
@@ -266,12 +212,6 @@ public:
/* The number of currently active jobs */
int _activeJobs;
/** We detected that another sync is required after this one */
bool _anotherSyncNeeded;
/* The maximum number of active job in parallel */
int maximumActiveJob();
bool isInSharedDirectory(const QString& file);
bool localFileNameClash(const QString& relfile);
@@ -307,26 +247,6 @@ signals:
};
// Job that wait for all the poll jobs to be completed
class CleanupPollsJob : public QObject {
Q_OBJECT
QVector< SyncJournalDb::PollInfo > _pollInfos;
Account *_account;
SyncJournalDb *_journal;
QString _localPath;
public:
explicit CleanupPollsJob(const QVector< SyncJournalDb::PollInfo > &pollInfos, Account *account,
SyncJournalDb *journal, const QString &localPath, QObject* parent = 0)
: QObject(parent), _pollInfos(pollInfos), _account(account), _journal(journal), _localPath(localPath) {}
void start();
signals:
void finished();
void aborted(const QString &error);
private slots:
void slotPollFinished();
};
}
#endif
+1 -1
Ver Arquivo
@@ -84,7 +84,7 @@ bool Progress::isWarningKind( SyncFileItem::Status kind)
{
return kind == SyncFileItem::SoftError || kind == SyncFileItem::NormalError
|| kind == SyncFileItem::FatalError || kind == SyncFileItem::FileIgnored
|| kind == SyncFileItem::Conflict || kind == SyncFileItem::Restoration;
|| kind == SyncFileItem::Conflict;
}
-4
Ver Arquivo
@@ -523,10 +523,6 @@ void PropagateDownloadFileLegacy::start()
_propagator->_journal->commit("download file start");
}
if (!_item._directDownloadUrl.isEmpty()) {
qDebug() << Q_FUNC_INFO << "Direct download URL" << _item._directDownloadUrl << "not supported with legacy propagator, will go via ownCloud server";
}
/* actually do the request */
int retry = 0;
+103 -466
Ver Arquivo
@@ -20,7 +20,6 @@
#include "utility.h"
#include "filesystem.h"
#include "propagatorjobs.h"
#include <json.h>
#include <QNetworkAccessManager>
#include <QFileInfo>
#include <QDir>
@@ -28,7 +27,7 @@
namespace Mirall {
static qint64 chunkSize() {
static uint chunkSize() {
static uint chunkSize;
if (!chunkSize) {
chunkSize = qgetenv("OWNCLOUD_CHUNK_SIZE").toUInt();
@@ -56,11 +55,6 @@ static SyncFileItem::Status classifyError(QNetworkReply::NetworkError nerror, in
return SyncFileItem::SoftError;
}
if (httpCode == 423) {
// Locked
return SyncFileItem::SoftError;
}
return SyncFileItem::NormalError;
}
@@ -70,7 +64,8 @@ void PUTFileJob::start() {
req.setRawHeader(it.key(), it.value());
}
setReply(davRequest("PUT", path(), req, _device.data()));
setReply(davRequest("PUT", path(), req, _device));
_device->setParent(reply());
setupConnections(reply());
if( reply()->error() != QNetworkReply::NoError ) {
@@ -88,75 +83,6 @@ void PUTFileJob::slotTimeout() {
reply()->abort();
}
void PollJob::start()
{
setTimeout(120 * 1000);
QUrl accountUrl = account()->url();
QUrl finalUrl = QUrl::fromUserInput(accountUrl.scheme() + QLatin1String("://") + accountUrl.authority()
+ (path().startsWith('/') ? QLatin1String("") : QLatin1Literal("/")) + path());
setReply(getRequest(finalUrl));
setupConnections(reply());
connect(reply(), SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(resetTimeout()));
AbstractNetworkJob::start();
}
bool PollJob::finished()
{
QNetworkReply::NetworkError err = reply()->error();
if (err != QNetworkReply::NoError) {
_item._httpErrorCode = reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
_item._status = classifyError(err, _item._httpErrorCode);
_item._errorString = reply()->errorString();
if (_item._status == SyncFileItem::FatalError || _item._httpErrorCode >= 400) {
if (_item._status != SyncFileItem::FatalError
&& _item._httpErrorCode != 503) {
SyncJournalDb::PollInfo info;
info._file = _item._file;
// no info._url removes it from the database
_journal->setPollInfo(info);
_journal->commit("remove poll info");
}
emit finishedSignal();
return true;
}
start();
return false;
}
bool ok = false;
QByteArray jsonData = reply()->readAll().trimmed();
qDebug() << Q_FUNC_INFO << ">" << jsonData << "<" << reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QVariantMap status = QtJson::parse(QString::fromUtf8(jsonData), ok).toMap();
if (!ok || status.isEmpty()) {
_item._errorString = tr("Invalid json reply from the poll URL");
_item._status = SyncFileItem::NormalError;
emit finishedSignal();
return true;
}
if (status["unfinished"].isValid()) {
start();
return false;
}
_item._errorString = status["error"].toString();
_item._status = _item._errorString.isEmpty() ? SyncFileItem::Success : SyncFileItem::NormalError;
_item._fileId = status["fileid"].toByteArray();
_item._etag = status["etag"].toByteArray();
_item._responseTimeStamp = responseTimestamp();
SyncJournalDb::PollInfo info;
info._file = _item._file;
// no info._url removes it from the database
_journal->setPollInfo(info);
_journal->commit("remove poll info");
emit finishedSignal();
return true;
}
void PropagateUploadFileQNAM::start()
{
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
@@ -185,159 +111,84 @@ void PropagateUploadFileQNAM::start()
_currentChunk = 0;
_duration.start();
_propagator->_activeJobs++;
emit progress(_item, 0);
emitReady();
this->startNextChunk();
}
UploadDevice::UploadDevice(QIODevice *file, qint64 start, qint64 size, BandwidthManager *bwm)
: QIODevice(file), _file(file), _read(0), _size(size), _start(start),
_bandwidthManager(bwm),
_bandwidthQuota(0),
_readWithProgress(0),
_bandwidthLimited(false), _choked(false)
{
qDebug() << Q_FUNC_INFO << start << size << chunkSize();
_bandwidthManager->registerUploadDevice(this);
_file = QPointer<QIODevice>(file);
}
struct ChunkDevice : QIODevice {
public:
QPointer<QIODevice> _file;
qint64 _read;
qint64 _size;
qint64 _start;
UploadDevice::~UploadDevice() {
if (_bandwidthManager) {
_bandwidthManager->unregisterUploadDevice(this);
ChunkDevice(QIODevice *file, qint64 start, qint64 size)
: QIODevice(file), _file(file), _read(0), _size(size), _start(start) {
_file = QPointer<QIODevice>(file);
_file.data()->seek(start);
}
}
qint64 UploadDevice::writeData(const char* , qint64 ) {
Q_ASSERT(!"write to read only device");
return 0;
}
qint64 UploadDevice::readData(char* data, qint64 maxlen) {
if (_file.isNull()) {
qDebug() << Q_FUNC_INFO << "Upload file object deleted during upload";
close();
return -1;
}
_file.data()->seek(_start + _read);
//qDebug() << Q_FUNC_INFO << maxlen << _read << _size << _bandwidthQuota;
if (_size - _read <= 0) {
// at end
qDebug() << Q_FUNC_INFO << _read << _size << _bandwidthQuota << "at end";
_bandwidthManager->unregisterUploadDevice(this);
return -1;
}
maxlen = qMin(maxlen, _size - _read);
if (maxlen == 0) {
virtual qint64 writeData(const char* , qint64 ) {
Q_ASSERT(!"write to read only device");
return 0;
}
if (isChoked()) {
qDebug() << Q_FUNC_INFO << this << "Upload Choked";
return 0;
}
if (isBandwidthLimited()) {
qDebug() << Q_FUNC_INFO << "BW LIMITED" << maxlen << _bandwidthQuota
<< qMin(maxlen, _bandwidthQuota);
maxlen = qMin(maxlen, _bandwidthQuota);
if (maxlen <= 0) { // no quota
qDebug() << Q_FUNC_INFO << "no quota";
return 0;
virtual qint64 readData(char* data, qint64 maxlen) {
if (_file.isNull()) {
qDebug() << Q_FUNC_INFO << "Upload file object deleted during upload";
close();
return -1;
}
_bandwidthQuota -= maxlen;
maxlen = qMin(maxlen, chunkSize() - _read);
if (maxlen == 0)
return 0;
qint64 ret = _file.data()->read(data, maxlen);
if (ret < 0)
return -1;
_read += ret;
return ret;
}
qDebug() << Q_FUNC_INFO << "reading limited=" << isBandwidthLimited()
<< "maxlen=" << maxlen << "quota=" << _bandwidthQuota;
qint64 ret = _file.data()->read(data, maxlen);
//qDebug() << Q_FUNC_INFO << "returning " << ret;
if (ret < 0)
return -1;
_read += ret;
//qDebug() << Q_FUNC_INFO << "returning2 " << ret << _read;
return ret;
}
void UploadDevice::slotJobUploadProgress(qint64 sent, qint64 t)
{
//qDebug() << Q_FUNC_INFO << sent << _read << t << _size << _bandwidthQuota;
if (sent == 0 || t == 0) {
return;
virtual bool atEnd() const {
if (_file.isNull()) {
qDebug() << Q_FUNC_INFO << "Upload file object deleted during upload";
return true;
}
return _read >= chunkSize() || _file.data()->atEnd();
}
_readWithProgress = sent;
}
bool UploadDevice::atEnd() const {
if (_file.isNull()) {
qDebug() << Q_FUNC_INFO << "Upload file object deleted during upload";
return true;
virtual qint64 size() const{
return _size;
}
// qDebug() << this << Q_FUNC_INFO << _read << chunkSize()
// << (_read >= chunkSize() || _file.data()->atEnd())
// << (_read >= _size);
return _file.data()->atEnd() || (_read >= _size);
}
qint64 UploadDevice::size() const{
// qDebug() << this << Q_FUNC_INFO << _size;
return _size;
}
qint64 bytesAvailable() const
{
return _size - _read + QIODevice::bytesAvailable();
}
qint64 UploadDevice::bytesAvailable() const
{
// qDebug() << this << Q_FUNC_INFO << _size << _read << QIODevice::bytesAvailable()
// << _size - _read + QIODevice::bytesAvailable();
return _size - _read + QIODevice::bytesAvailable();
}
// random access, we can seek
bool UploadDevice::isSequential() const{
return false;
}
bool UploadDevice::seek ( qint64 pos ) {
if (_file.isNull()) {
qDebug() << Q_FUNC_INFO << "Upload file object deleted during upload";
close();
// random access, we can seek
virtual bool isSequential() const{
return false;
}
qDebug() << this << Q_FUNC_INFO << pos << _read;
_read = pos;
return _file.data()->seek(pos + _start);
}
void UploadDevice::giveBandwidthQuota(qint64 bwq) {
// qDebug() << Q_FUNC_INFO << bwq;
if (!atEnd()) {
_bandwidthQuota = bwq;
// qDebug() << Q_FUNC_INFO << bwq << "emitting readyRead()" << _read << _readWithProgress;
QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection); // tell QNAM that we have quota
virtual bool seek ( qint64 pos ) {
if (_file.isNull()) {
qDebug() << Q_FUNC_INFO << "Upload file object deleted during upload";
close();
return false;
}
_read = pos;
return _file.data()->seek(pos + _start);
}
}
void UploadDevice::setBandwidthLimited(bool b) {
_bandwidthLimited = b;
QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection);
}
void UploadDevice::setChoked(bool b) {
_choked = b;
if (!_choked) {
QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection);
}
}
};
void PropagateUploadFileQNAM::startNextChunk()
{
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
return;
if (! _jobs.isEmpty() && _currentChunk + _startChunk >= _chunkCount - 1) {
// Don't do parallel upload of chunk if this might be the last chunk because the server cannot handle that
// https://github.com/owncloud/core/issues/11106
// We return now and when the _jobs will be finished we will proceed the last chunk
return;
}
/*
* // If the source file has changed during upload, it is detected and the
@@ -355,7 +206,6 @@ void PropagateUploadFileQNAM::startNextChunk()
quint64 fileSize = _item._size;
QMap<QByteArray, QByteArray> headers;
headers["OC-Total-Length"] = QByteArray::number(fileSize);
headers["OC-Async"] = "1";
headers["Content-Type"] = "application/octet-stream";
headers["X-OC-Mtime"] = QByteArray::number(qint64(_item._modtime));
if (!_item._etag.isEmpty() && _item._etag != "empty_etag") {
@@ -365,7 +215,7 @@ void PropagateUploadFileQNAM::startNextChunk()
}
QString path = _item._file;
UploadDevice *device = 0;
QIODevice *device = 0;
if (_chunkCount > 1) {
int sendingChunk = (_currentChunk + _startChunk) % _chunkCount;
// XOR with chunk size to make sure everything goes well if chunk size change between runs
@@ -379,9 +229,9 @@ void PropagateUploadFileQNAM::startNextChunk()
currentChunkSize = chunkSize();
}
}
device = new UploadDevice(_file, chunkSize() * quint64(sendingChunk), currentChunkSize, &_propagator->_bandwidthManager);
device = new ChunkDevice(_file, chunkSize() * sendingChunk, currentChunkSize);
} else {
device = new UploadDevice(_file, 0, fileSize, &_propagator->_bandwidthManager);
device = _file;
}
bool isOpen = true;
@@ -390,31 +240,11 @@ void PropagateUploadFileQNAM::startNextChunk()
}
if( isOpen ) {
PUTFileJob* job = new PUTFileJob(AccountManager::instance()->account(), _propagator->_remoteFolder + path, device, headers, _currentChunk);
_jobs.append(job);
_currentChunk++;
connect(job, SIGNAL(finishedSignal()), this, SLOT(slotPutFinished()));
connect(job, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(slotUploadProgress(qint64,qint64)));
connect(job, SIGNAL(uploadProgress(qint64,qint64)), device, SLOT(slotJobUploadProgress(qint64,qint64)));
connect(job, SIGNAL(destroyed(QObject*)), this, SLOT(slotJobDestroyed(QObject*)));
job->start();
_propagator->_activeJobs++;
QByteArray env = qgetenv("OWNCLOUD_PARALLEL_CHUNK");
bool parallelChunkUpload = env=="true" || env =="1";;
if (_currentChunk + _startChunk >= _chunkCount - 1) {
// Don't do parallel upload of chunk if this might be the last chunk because the server cannot handle that
// https://github.com/owncloud/core/issues/11106
parallelChunkUpload = false;
}
if (parallelChunkUpload && (_propagator->_activeJobs < _propagator->maximumActiveJob())
&& _currentChunk < _chunkCount ) {
startNextChunk();
}
if (!parallelChunkUpload || _chunkCount - _currentChunk <= 0) {
emitReady();
}
_job = new PUTFileJob(AccountManager::instance()->account(), _propagator->_remoteFolder + path, device, headers);
_job->setTimeout(_propagator->httpTimeout() * 1000);
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotPutFinished()));
connect(_job, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(slotUploadProgress(qint64,qint64)));
_job->start();
} else {
qDebug() << "ERR: Could not open upload file: " << device->errorString();
done( SyncFileItem::NormalError, device->errorString() );
@@ -427,7 +257,6 @@ void PropagateUploadFileQNAM::slotPutFinished()
{
PUTFileJob *job = qobject_cast<PUTFileJob *>(sender());
Q_ASSERT(job);
slotJobDestroyed(job); // remove it from the _jobs list
qDebug() << Q_FUNC_INFO << job->reply()->request().url() << "FINISHED WITH STATUS"
<< job->reply()->error()
@@ -435,16 +264,10 @@ void PropagateUploadFileQNAM::slotPutFinished()
<< job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute)
<< job->reply()->attribute(QNetworkRequest::HttpReasonPhraseAttribute);
_propagator->_activeJobs--;
if (_finished) {
// We have send the finished signal already. We don't need to handle any remaining jobs
return;
}
QNetworkReply::NetworkError err = job->reply()->error();
if (err != QNetworkReply::NoError) {
_item._httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
_propagator->_activeJobs--;
if(checkForProblemsWithShared(_item._httpErrorCode,
tr("The file was edited locally but is part of a read only share. "
"It is restored and your edit is in the conflict file."))) {
@@ -456,11 +279,7 @@ void PropagateUploadFileQNAM::slotPutFinished()
qDebug() << replyContent; // display the XML error in the debug
QRegExp rx("<s:message>(.*)</s:message>"); // Issue #1366: display server exception
if (rx.indexIn(QString::fromUtf8(replyContent)) != -1) {
if (_item._httpErrorCode == 423) {
errorString = rx.cap(1); // For "Locked", the library user doesn't want all the stuff except the <s:message> contents
} else {
errorString += QLatin1String(" (") + rx.cap(1) + QLatin1Char(')');
}
errorString += QLatin1String(" (") + rx.cap(1) + QLatin1Char(')');
}
if (_item._httpErrorCode == 412) {
@@ -473,33 +292,19 @@ void PropagateUploadFileQNAM::slotPutFinished()
return;
}
_item._httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// The server needs some time to process the request and provide with a poll URL
if (_item._httpErrorCode == 202) {
_finished = true;
QString path = QString::fromUtf8(job->reply()->rawHeader("OC-Finish-Poll"));
if (path.isEmpty()) {
done(SyncFileItem::NormalError, tr("Poll URL missing"));
return;
}
startPollJob(path);
return;
}
bool finished = job->reply()->hasRawHeader("ETag");
if (!finished) {
QFileInfo fi(_propagator->_localDir + _item._file);
if( !fi.exists() ) {
_finished = true;
_propagator->_activeJobs--;
done(SyncFileItem::SoftError, tr("The local file was removed during sync."));
return;
}
if (Utility::qDateTimeToTime_t(fi.lastModified()) != _item._modtime) {
qDebug() << "The local file has changed during upload:" << _item._modtime << "!=" << Utility::qDateTimeToTime_t(fi.lastModified()) << fi.lastModified();
_finished = true;
_propagator->_anotherSyncNeeded = true;
_propagator->_activeJobs--;
done(SyncFileItem::SoftError, tr("Local file changed during sync."));
// FIXME: the legacy code was retrying for a few seconds.
// and also checking that after the last chunk, and removed the file in case of INSTRUCTION_NEW
@@ -507,24 +312,16 @@ void PropagateUploadFileQNAM::slotPutFinished()
}
// Proceed to next chunk.
_currentChunk++;
if (_currentChunk >= _chunkCount) {
if (!_jobs.empty()) {
// just wait for the other job to finish.
return;
}
_finished = true;
_propagator->_activeJobs--;
done(SyncFileItem::NormalError, tr("The server did not acknowledge the last chunk. (No e-tag were present)"));
return;
}
SyncJournalDb::UploadInfo pi;
pi._valid = true;
auto currentChunk = job->_chunk;
foreach (auto *job, _jobs) {
// Take the minimum finished one
currentChunk = qMin(currentChunk, job->_chunk - 1);
}
pi._chunk = (currentChunk + _startChunk + 1) % _chunkCount ; // next chunk to start with
pi._chunk = (_currentChunk + _startChunk) % _chunkCount; // next chunk to start with
pi._transferid = _transferId;
pi._modtime = Utility::qDateTimeFromTime_t(_item._modtime);
_propagator->_journal->setUploadInfo(_item._file, pi);
@@ -534,7 +331,7 @@ void PropagateUploadFileQNAM::slotPutFinished()
}
// the following code only happens after all chunks were uploaded.
_finished = true;
//
// the file id should only be empty for new files up- or downloaded
QByteArray fid = job->reply()->rawHeader("OC-FileID");
if( !fid.isEmpty() ) {
@@ -566,6 +363,8 @@ void PropagateUploadFileQNAM::finalize(const SyncFileItem &copy)
_item._etag = copy._etag;
_item._fileId = copy._fileId;
_propagator->_activeJobs--;
_item._requestDuration = _duration.elapsed();
_propagator->_journal->setFileRecord(SyncJournalFileRecord(_item, _propagator->_localDir + _item._file));
@@ -573,115 +372,37 @@ void PropagateUploadFileQNAM::finalize(const SyncFileItem &copy)
_propagator->_journal->setUploadInfo(_item._file, SyncJournalDb::UploadInfo());
_propagator->_journal->commit("upload file start");
qDebug() << Q_FUNC_INFO << "msec=" <<_duration.elapsed();
done(SyncFileItem::Success);
}
void PropagateUploadFileQNAM::slotUploadProgress(qint64 sent, qint64 t)
void PropagateUploadFileQNAM::slotUploadProgress(qint64 sent, qint64)
{
int progressChunk = _currentChunk + _startChunk - 1;
int progressChunk = _currentChunk + _startChunk;
if (progressChunk >= _chunkCount)
progressChunk = _currentChunk - 1;
quint64 amount = progressChunk * chunkSize();
sender()->setProperty("byteWritten", sent);
if (_jobs.count() > 1) {
amount -= (_jobs.count() -1) * chunkSize();
foreach (QObject *j, _jobs) {
amount += j->property("byteWritten").toULongLong();
}
} else {
amount += sent;
}
emit progress(_item, amount);
progressChunk = _currentChunk;
emit progress(_item, sent + _currentChunk * chunkSize());
}
void PropagateUploadFileQNAM::startPollJob(const QString& path)
{
PollJob* job = new PollJob(AccountManager::instance()->account(), path, _item,
_propagator->_journal, _propagator->_localDir, this);
connect(job, SIGNAL(finishedSignal()), SLOT(slotPollFinished()));
SyncJournalDb::PollInfo info;
info._file = _item._file;
info._url = path;
info._modtime = _item._modtime;
_propagator->_journal->setPollInfo(info);
_propagator->_journal->commit("add poll info");
job->start();
}
void PropagateUploadFileQNAM::slotPollFinished()
{
PollJob *job = qobject_cast<PollJob *>(sender());
Q_ASSERT(job);
if (job->_item._status != SyncFileItem::Success) {
done(job->_item._status, job->_item._errorString);
return;
}
finalize(job->_item);
}
void PropagateUploadFileQNAM::slotJobDestroyed(QObject* job)
{
_jobs.erase(std::remove(_jobs.begin(), _jobs.end(), job) , _jobs.end());
}
void PropagateUploadFileQNAM::abort()
{
foreach(auto *job, _jobs) {
if (job->reply()) {
qDebug() << Q_FUNC_INFO << job << this->_item._file;
job->reply()->abort();
}
if (_job && _job->reply()) {
qDebug() << Q_FUNC_INFO << this->_item._file;
_job->reply()->abort();
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// DOES NOT take owncership of the device.
GETFileJob::GETFileJob(Account* account, const QString& path, QFile *device,
const QMap<QByteArray, QByteArray> &headers, const QByteArray &expectedEtagForResume,
quint64 _resumeStart, QObject* parent)
: AbstractNetworkJob(account, path, parent),
_device(device), _headers(headers), _expectedEtagForResume(expectedEtagForResume),
_resumeStart(_resumeStart) , _errorStatus(SyncFileItem::NoStatus)
, _bandwidthLimited(false), _bandwidthChoked(false), _bandwidthQuota(0), _bandwidthManager(0)
, _hasEmittedFinishedSignal(false)
{
}
GETFileJob::GETFileJob(Account* account, const QUrl& url, QFile *device,
const QMap<QByteArray, QByteArray> &headers, const QByteArray &expectedEtagForResume,
quint64 resumeStart, QObject* parent)
: AbstractNetworkJob(account, url.toEncoded(), parent),
_device(device), _headers(headers), _expectedEtagForResume(expectedEtagForResume), _resumeStart(resumeStart),
_errorStatus(SyncFileItem::NoStatus), _directDownloadUrl(url)
, _bandwidthLimited(false), _bandwidthChoked(false), _bandwidthQuota(0), _bandwidthManager(0)
, _hasEmittedFinishedSignal(false)
{
}
void GETFileJob::start() {
QNetworkRequest req;
for(QMap<QByteArray, QByteArray>::const_iterator it = _headers.begin(); it != _headers.end(); ++it) {
req.setRawHeader(it.key(), it.value());
}
if (_directDownloadUrl.isEmpty()) {
setReply(davRequest("GET", path(), req));
} else {
// Use direct URL
setReply(davRequest("GET", _directDownloadUrl, req));
}
setReply(davRequest("GET", path(), req));
setupConnections(reply());
reply()->setReadBufferSize(16 * 1024); // keep low so we can easier limit the bandwidth
qDebug() << Q_FUNC_INFO << _bandwidthManager << _bandwidthChoked << _bandwidthLimited;
if (_bandwidthManager) {
_bandwidthManager->registerDownloadJob(this);
}
reply()->setReadBufferSize(128 * 1024);
if( reply()->error() != QNetworkReply::NoError ) {
qWarning() << Q_FUNC_INFO << " Network error: " << reply()->errorString();
@@ -696,31 +417,23 @@ void GETFileJob::start() {
void GETFileJob::slotMetaDataChanged()
{
// For some reason setting the read buffer in GETFileJob::start doesn't seem to go
// through the HTTP layer thread(?)
reply()->setReadBufferSize(16 * 1024);
if (reply()->error() != QNetworkReply::NoError
|| reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() / 100 != 2) {
// We will handle the error when the job is finished.
return;
}
_etag = parseEtag(reply()->rawHeader("Etag"));
if (!_directDownloadUrl.isEmpty() && !_etag.isEmpty()) {
qDebug() << Q_FUNC_INFO << "Direct download used, ignoring server ETag" << _etag;
_etag = QByteArray(); // reset received ETag
} else if (!_directDownloadUrl.isEmpty()) {
// All fine, ETag empty and directDownloadUrl used
} else if (_etag.isEmpty()) {
QByteArray etag = parseEtag(reply()->rawHeader("Etag"));
if (etag.isEmpty()) {
qDebug() << Q_FUNC_INFO << "No E-Tag reply by server, considering it invalid";
_errorString = tr("No E-Tag received from server, check Proxy/Gateway");
_errorStatus = SyncFileItem::NormalError;
reply()->abort();
return;
} else if (!_expectedEtagForResume.isEmpty() && _expectedEtagForResume != _etag) {
} else if (!_expectedEtagForResume.isEmpty() && _expectedEtagForResume != etag) {
qDebug() << Q_FUNC_INFO << "We received a different E-Tag for resuming!"
<< _expectedEtagForResume << "vs" << _etag;
<< _expectedEtagForResume << "vs" << etag;
_errorString = tr("We received a different E-Tag for resuming. Retrying next time.");
_errorStatus = SyncFileItem::NormalError;
reply()->abort();
@@ -756,62 +469,13 @@ void GETFileJob::slotMetaDataChanged()
}
void GETFileJob::setBandwidthManager(BandwidthManager *bwm)
{
_bandwidthManager = bwm;
}
void GETFileJob::setChoked(bool c)
{
_bandwidthChoked = c;
QMetaObject::invokeMethod(this, "slotReadyRead", Qt::QueuedConnection);
}
void GETFileJob::setBandwidthLimited(bool b)
{
_bandwidthLimited = b;
QMetaObject::invokeMethod(this, "slotReadyRead", Qt::QueuedConnection);
}
void GETFileJob::giveBandwidthQuota(qint64 q)
{
_bandwidthQuota = q;
qDebug() << Q_FUNC_INFO << "Got" << q << "bytes";
QMetaObject::invokeMethod(this, "slotReadyRead", Qt::QueuedConnection);
}
qint64 GETFileJob::currentDownloadPosition()
{
if (_device && _device->pos() > 0 && _device->pos() > _resumeStart) {
return _device->pos();
}
return _resumeStart;
}
void GETFileJob::slotReadyRead()
{
int bufferSize = qMin(1024*8ll , reply()->bytesAvailable());
QByteArray buffer(bufferSize, Qt::Uninitialized);
//qDebug() << Q_FUNC_INFO << reply()->bytesAvailable() << reply()->isOpen() << reply()->isFinished();
while(reply()->bytesAvailable() > 0) {
if (_bandwidthChoked) {
qDebug() << Q_FUNC_INFO << "Download choked";
break;
}
qint64 toRead = bufferSize;
if (_bandwidthLimited) {
toRead = qMin(qint64(bufferSize), _bandwidthQuota);
if (toRead == 0) {
qDebug() << Q_FUNC_INFO << "Out of quota";
break;
}
_bandwidthQuota -= toRead;
//qDebug() << Q_FUNC_INFO << "Reading" << toRead << "remaining" << _bandwidthQuota;
}
qint64 r = reply()->read(buffer.data(), toRead);
qint64 r = reply()->read(buffer.data(), bufferSize);
if (r < 0) {
_errorString = reply()->errorString();
_errorStatus = SyncFileItem::NormalError;
@@ -830,26 +494,6 @@ void GETFileJob::slotReadyRead()
}
}
resetTimeout();
//qDebug() << Q_FUNC_INFO << "END" << reply()->isFinished() << reply()->bytesAvailable() << _hasEmittedFinishedSignal;
if (reply()->isFinished() && reply()->bytesAvailable() == 0) {
qDebug() << Q_FUNC_INFO << "Actually finished!";
if (_bandwidthManager) {
_bandwidthManager->unregisterDownloadJob(this);
}
if (!_hasEmittedFinishedSignal) {
emit finishedSignal();
}
_hasEmittedFinishedSignal = true;
deleteLater();
}
}
void GETFileJob::slotTimeout()
{
_errorString = tr("Connection Timeout");
_errorStatus = SyncFileItem::FatalError;
reply()->abort();
}
void PropagateDownloadFileQNAM::start()
@@ -859,7 +503,7 @@ void PropagateDownloadFileQNAM::start()
qDebug() << Q_FUNC_INFO << _item._file << _propagator->_activeJobs;
// do a klaas' case clash check.
// do a case clash check.
if( _propagator->localFileNameClash(_item._file) ) {
done( SyncFileItem::NormalError, tr("File %1 can not be downloaded because of a local file name clash!")
.arg(QDir::toNativeSeparators(_item._file)) );
@@ -911,6 +555,8 @@ void PropagateDownloadFileQNAM::start()
QMap<QByteArray, QByteArray> headers;
/* Allow compressed content by setting the header */
//headers["Accept-Encoding"] = "gzip";
if (_tmpFile.size() > 0) {
quint64 done = _tmpFile.size();
@@ -925,23 +571,10 @@ void PropagateDownloadFileQNAM::start()
_startSize = done;
}
if (_item._directDownloadUrl.isEmpty()) {
// Normal job, download from oC instance
_job = new GETFileJob(AccountManager::instance()->account(),
_propagator->_remoteFolder + _item._file,
&_tmpFile, headers, expectedEtagForResume, _startSize);
} else {
// We were provided a direct URL, use that one
if (!_item._directDownloadCookies.isEmpty()) {
headers["Cookie"] = _item._directDownloadCookies.toUtf8();
}
QUrl url = QUrl::fromUserInput(_item._directDownloadUrl);
_job = new GETFileJob(AccountManager::instance()->account(),
url,
&_tmpFile, headers, expectedEtagForResume, _startSize);
qDebug() << Q_FUNC_INFO << "directDownloadUrl given for " << _item._file << _item._directDownloadUrl << headers["Cookie"];
}
_job->setBandwidthManager(&_propagator->_bandwidthManager);
_job = new GETFileJob(AccountManager::instance()->account(),
_propagator->_remoteFolder + _item._file,
&_tmpFile, headers, expectedEtagForResume, _startSize);
_job->setTimeout(_propagator->httpTimeout() * 1000);
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotGetFinished()));
connect(_job, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(slotDownloadProgress(qint64,qint64)));
_propagator->_activeJobs ++;
@@ -978,11 +611,7 @@ void PropagateDownloadFileQNAM::slotGetFinished()
return;
}
if (!job->etag().isEmpty()) {
// The etag will be empty if we used a direct download URL.
// (If it was really empty by the server, the GETFileJob will have errored
_item._etag = parseEtag(job->etag());
}
_item._etag = parseEtag(job->reply()->rawHeader("Etag"));
_item._requestDuration = job->duration();
_item._responseTimeStamp = job->responseTimestamp();
@@ -1064,5 +693,13 @@ void PropagateDownloadFileQNAM::abort()
_job->reply()->abort();
}
void GETFileJob::slotTimeout()
{
_errorString = tr("Connection Timeout");
_errorStatus = SyncFileItem::FatalError;
reply()->abort();
}
}
+17 -77
Ver Arquivo
@@ -51,17 +51,15 @@ public:
class PUTFileJob : public AbstractNetworkJob {
Q_OBJECT
QSharedPointer<QIODevice> _device;
QIODevice* _device;
QMap<QByteArray, QByteArray> _headers;
QString _errorString;
public:
// Takes ownership of the device
explicit PUTFileJob(Account* account, const QString& path, QIODevice *device,
const QMap<QByteArray, QByteArray> &headers, int chunk, QObject* parent = 0)
: AbstractNetworkJob(account, path, parent), _device(device), _headers(headers), _chunk(chunk) {}
int _chunk;
const QMap<QByteArray, QByteArray> &headers, QObject* parent = 0)
: AbstractNetworkJob(account, path, parent), _device(device), _headers(headers) {}
virtual void start();
@@ -82,55 +80,26 @@ signals:
void uploadProgress(qint64,qint64);
};
class PollJob : public AbstractNetworkJob {
Q_OBJECT
SyncJournalDb *_journal;
QString _localPath;
public:
SyncFileItem _item;
// Takes ownership of the device
explicit PollJob(Account* account, const QString &path, const SyncFileItem &item,
SyncJournalDb *journal, const QString &localPath, QObject *parent)
: AbstractNetworkJob(account, path, parent), _journal(journal), _localPath(localPath), _item(item) {}
void start() Q_DECL_OVERRIDE;
bool finished() Q_DECL_OVERRIDE;
void slotTimeout() Q_DECL_OVERRIDE {
// emit finishedSignal(false);
// deleteLater();
qDebug() << Q_FUNC_INFO;
reply()->abort();
}
signals:
void finishedSignal();
};
class PropagateUploadFileQNAM : public PropagateItemJob {
Q_OBJECT
QPointer<PUTFileJob> _job;
QFile *_file;
int _startChunk;
int _currentChunk;
int _chunkCount;
int _transferId;
QElapsedTimer _duration;
QVector<PUTFileJob*> _jobs;
bool _finished;
public:
PropagateUploadFileQNAM(OwncloudPropagator* propagator,const SyncFileItem& item)
: PropagateItemJob(propagator, item), _startChunk(0), _currentChunk(0), _chunkCount(0), _transferId(0), _finished(false) {}
: PropagateItemJob(propagator, item), _startChunk(0), _currentChunk(0), _chunkCount(0), _transferId(0) {}
void start();
private slots:
void slotPutFinished();
void slotPollFinished();
void slotUploadProgress(qint64,qint64);
void abort();
void startNextChunk();
void finalize(const SyncFileItem&);
void slotJobDestroyed(QObject *job);
private:
void startPollJob(const QString& path);
};
@@ -142,53 +111,22 @@ class GETFileJob : public AbstractNetworkJob {
QByteArray _expectedEtagForResume;
quint64 _resumeStart;
SyncFileItem::Status _errorStatus;
QUrl _directDownloadUrl;
QByteArray _etag;
bool _bandwidthLimited; // if _bandwidthQuota will be used
bool _bandwidthChoked; // if download is paused (won't read on readyRead())
qint64 _bandwidthQuota;
QPointer<BandwidthManager> _bandwidthManager;
bool _hasEmittedFinishedSignal;
public:
// DOES NOT take owncership of the device.
explicit GETFileJob(Mirall::Account* account, const QString& path, QFile* device,
const QMap<QByteArray, QByteArray> &headers, const QByteArray& expectedEtagForResume,
quint64 _resumeStart, QObject* parent = 0);
// For directDownloadUrl:
explicit GETFileJob(Mirall::Account* account, const QUrl& url, QFile* device,
const QMap<QByteArray, QByteArray> &headers, const QByteArray& expectedEtagForResume,
quint64 resumeStart, QObject* parent = 0);
virtual ~GETFileJob() {
if (_bandwidthManager) {
_bandwidthManager->unregisterDownloadJob(this);
}
}
explicit GETFileJob(Account* account, const QString& path, QFile *device,
const QMap<QByteArray, QByteArray> &headers, QByteArray expectedEtagForResume,
quint64 resumeStart, QObject* parent = 0)
: AbstractNetworkJob(account, path, parent),
_device(device), _headers(headers), _expectedEtagForResume(expectedEtagForResume),
_resumeStart(resumeStart), _errorStatus(SyncFileItem::NoStatus) {}
virtual void start();
virtual bool finished() {
qDebug() << Q_FUNC_INFO << reply()->bytesAvailable() << _hasEmittedFinishedSignal;
if (reply()->bytesAvailable()) {
qDebug() << Q_FUNC_INFO << "Not all read yet because of bandwidth limits";
return false;
} else {
if (_bandwidthManager) {
_bandwidthManager->unregisterDownloadJob(this);
}
if (!_hasEmittedFinishedSignal) {
emit finishedSignal();
}
_hasEmittedFinishedSignal = true;
return true; // discard
}
emit finishedSignal();
return true;
}
void setBandwidthManager(BandwidthManager *bwm);
void setChoked(bool c);
void setBandwidthLimited(bool b);
void giveBandwidthQuota(qint64 q);
qint64 currentDownloadPosition();
QString errorString() {
return _errorString.isEmpty() ? reply()->errorString() : _errorString;
};
@@ -197,8 +135,6 @@ public:
virtual void slotTimeout();
QByteArray &etag() { return _etag; }
signals:
void finishedSignal();
@@ -225,6 +161,10 @@ private slots:
void abort();
void downloadFinished();
void slotDownloadProgress(qint64,qint64);
};
}
+14 -41
Ver Arquivo
@@ -154,35 +154,6 @@ void PropagateRemoteRemove::start()
done(SyncFileItem::Success);
}
/* The list of properties that is fetched in PropFind after a MKCOL */
static const ne_propname ls_props[] = {
{ "DAV:", "getetag"},
{ "http://owncloud.org/ns", "id"},
{ NULL, NULL }
};
/*
* Parse the PROPFIND result after a MKCOL
*/
void PropagateRemoteMkdir::propfind_results(void *userdata,
const ne_uri *uri,
const ne_prop_result_set *set)
{
PropagateRemoteMkdir *job = static_cast<PropagateRemoteMkdir *>(userdata);
job->_item._etag = parseEtag(ne_propset_value( set, &ls_props[0] ));
const char* fileId = ne_propset_value( set, &ls_props[1] );
if (fileId) {
job->_item._fileId = fileId;
qDebug() << "MKCOL: " << uri << " FileID set it to " << fileId;
// save the file id already so we can detect rename
SyncJournalFileRecord record(job->_item, job->_propagator->_localDir + job->_item._renameTarget);
job->_propagator->_journal->setFileRecord(record);
}
}
void PropagateRemoteMkdir::start()
{
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
@@ -203,16 +174,6 @@ void PropagateRemoteMkdir::start()
return;
}
// Get the fileid
// This is required so that wa can detect moves even if the folder is renamed on the server
// while files are still uploading
// TODO: Now we have to do a propfind because the server does not give the file id in the request
// https://github.com/owncloud/core/issues/9000
ne_propfind_handler *hdl = ne_propfind_create(_propagator->_session, uri.data(), 0);
ne_propfind_named(hdl, ls_props, propfind_results, this);
ne_propfind_destroy(hdl);
done(SyncFileItem::Success);
}
@@ -265,7 +226,16 @@ void PropagateRemoteRename::start()
return;
if (_item._file == _item._renameTarget) {
// The parents has been renamed already so there is nothing more to do.
if (!_item._isDirectory) {
// The parents has been renamed already so there is nothing more to do.
// But we still need to fetch the new ETAG
// FIXME maybe do a recusrsive propfind after having moved the parent.
// Note: we also update the mtime because the server do not keep the mtime when moving files
QScopedPointer<char, QScopedPointerPodDeleter> uri2(
ne_path_escape((_propagator->_remoteDir + _item._renameTarget).toUtf8()));
if (!updateMTimeAndETag(uri2.data(), _item._modtime))
return;
}
} else if (_item._file == QLatin1String("Shared") ) {
// Check if it is the toplevel Shared folder and do not propagate it.
if( QFile::rename( _propagator->_localDir + _item._renameTarget, _propagator->_localDir + QLatin1String("Shared")) ) {
@@ -293,6 +263,9 @@ void PropagateRemoteRename::start()
if (updateErrorFromSession(rc)) {
return;
}
if (!updateMTimeAndETag(uri2.data(), _item._modtime))
return;
}
// Wed, 15 Nov 1995 06:25:24 GMT
QDateTime dt = QDateTime::currentDateTimeUtc();
@@ -352,7 +325,7 @@ bool PropagateNeonJob::updateErrorFromSession(int neon_code, ne_request* req, in
if (ignoreHttpCode && httpStatusCode == ignoreHttpCode)
return false;
done((httpStatusCode != 423) ? SyncFileItem::NormalError : SyncFileItem::SoftError, errorString);
done(SyncFileItem::NormalError, errorString);
return true;
case NE_LOOKUP: /* Server or proxy hostname lookup failed */
case NE_AUTH: /* User authentication failed on server */
-3
Ver Arquivo
@@ -94,9 +94,6 @@ class PropagateRemoteMkdir : public PropagateNeonJob {
public:
PropagateRemoteMkdir (OwncloudPropagator* propagator,const SyncFileItem& item) : PropagateNeonJob(propagator, item) {}
void start();
private:
static void propfind_results(void *userdata, const ne_uri *uri, const ne_prop_result_set *set);
friend class PropagateDirectory; // So it can access the _item;
};
class PropagateLocalRename : public PropagateItemJob {
Q_OBJECT
+42 -71
Ver Arquivo
@@ -19,7 +19,6 @@
#include "mirall/folderman.h"
#include "mirall/folder.h"
#include "mirall/utility.h"
#include "mirall/theme.h"
#include <QDebug>
#include <QUrl>
@@ -27,11 +26,12 @@
#include <QLocalServer>
#include <QMetaObject>
#include <QStringList>
#include <QScopedPointer>
#include <QFile>
#include <QDir>
#include <QApplication>
#include "mirall/utility.h"
namespace Mirall {
#define DEBUG qDebug() << "SocketApi: "
@@ -42,8 +42,7 @@ SocketApi::SocketApi(QObject* parent, const QUrl& localFile)
{
QString socketPath;
if (Utility::isWindows()) {
socketPath = QLatin1String("\\\\.\\pipe\\")
+ Theme::instance()->appName();
socketPath = QLatin1String("\\\\.\\pipe\\");
} else {
socketPath = localFile.toLocalFile();
@@ -52,15 +51,14 @@ SocketApi::SocketApi(QObject* parent, const QUrl& localFile)
// setup socket
_localServer = new QLocalServer(this);
QLocalServer::removeServer(socketPath);
if(!_localServer->listen(socketPath)) {
if(!_localServer->listen(socketPath))
DEBUG << "can't start server" << socketPath;
} else {
DEBUG << "server started, listening at " << socketPath;
}
connect(_localServer, SIGNAL(newConnection()), this, SLOT(slotNewConnection()));
else
DEBUG << "server started" << socketPath;
connect(_localServer, SIGNAL(newConnection()), this, SLOT(onNewConnection()));
// folder watcher
connect(FolderMan::instance(), SIGNAL(folderSyncStateChange(QString)), SLOT(slotSyncStateChanged(QString)));
connect(FolderMan::instance(), SIGNAL(folderSyncStateChange(QString)), SLOT(onSyncStateChanged(QString)));
}
SocketApi::~SocketApi()
@@ -69,14 +67,11 @@ SocketApi::~SocketApi()
_localServer->close();
}
void SocketApi::slotNewConnection()
void SocketApi::onNewConnection()
{
QLocalSocket* socket = _localServer->nextPendingConnection();
if( ! socket ) {
return;
}
DEBUG << "New connection " << socket;
connect(socket, SIGNAL(readyRead()), this, SLOT(slotReadSocket()));
connect(socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
connect(socket, SIGNAL(disconnected()), this, SLOT(onLostConnection()));
Q_ASSERT(socket->readAll().isEmpty());
@@ -92,12 +87,13 @@ void SocketApi::onLostConnection()
}
void SocketApi::slotReadSocket()
void SocketApi::onReadyRead()
{
QLocalSocket* socket = qobject_cast<QLocalSocket*>(sender());
Q_ASSERT(socket);
while(socket->canReadLine()) {
while(socket->canReadLine())
{
QString line = QString::fromUtf8(socket->readLine()).trimmed();
QString command = line.split(":").first();
QString function = QString(QLatin1String("command_")).append(command);
@@ -106,15 +102,18 @@ void SocketApi::slotReadSocket()
int indexOfMethod = this->metaObject()->indexOfMethod(functionWithArguments.toAscii());
QString argument = line.remove(0, command.length()+1).trimmed();
if(indexOfMethod != -1) {
if(indexOfMethod != -1)
{
QMetaObject::invokeMethod(this, function.toAscii(), Q_ARG(QString, argument), Q_ARG(QLocalSocket*, socket));
} else {
}
else
{
DEBUG << "The command is not supported by this version of the client:" << command << "with argument:" << argument;
}
}
}
void SocketApi::slotSyncStateChanged(const QString&)
void SocketApi::onSyncStateChanged(const QString&)
{
broadcastMessage("UPDATE_VIEW");
}
@@ -138,94 +137,66 @@ void SocketApi::broadcastMessage(const QString& message)
void SocketApi::command_RETRIEVE_FOLDER_STATUS(const QString& argument, QLocalSocket* socket)
{
bool checkForSyncDirsOnly = false;
qDebug() << Q_FUNC_INFO << argument;
//TODO: do security checks?!
Folder* folder = FolderMan::instance()->folderForPath( argument );
// this can happen in offline mode e.g.: nothing to worry about
if (!folder) {
if(!folder)
{
DEBUG << "folder offline or not watched:" << argument;
checkForSyncDirsOnly = true;
return;
}
QDir dir(argument);
QStringList dirEntries;
if( checkForSyncDirsOnly ) {
dirEntries = dir.entryList(QDir::Dirs);
} else {
dirEntries = dir.entryList( QDir::AllEntries | QDir::NoDotAndDotDot );
}
foreach(const QString entry, dirEntries) {
foreach(QString entry, dir.entryList(QDir::AllEntries|QDir::NoDotAndDotDot))
{
QString absoluteFilePath = dir.absoluteFilePath(entry);
QString statusString;
if( checkForSyncDirsOnly ) {
Folder *f = FolderMan::instance()->folderForPath(absoluteFilePath);
if( f ) {
statusString = QLatin1String("SYNCDIR");
SyncFileStatus sfs = f->recursiveFolderStatus("");
if (sfs == FILE_STATUS_ERROR) {
statusString.append(QLatin1String("_ERR"));
} else if( sfs == FILE_STATUS_EVAL ) {
statusString.append(QLatin1String("_EVAL"));
} else if( sfs == FILE_STATUS_SYNC ) {
// all cool.
} else {
qDebug() << "Unexpected directory status!";
}
}
} else {
SyncFileStatus fileStatus = folder->fileStatus(absoluteFilePath.mid(folder->path().length()));
switch(fileStatus)
{
SyncFileStatus fileStatus = folder->fileStatus(absoluteFilePath.mid(folder->path().length()));
switch(fileStatus)
{
case FILE_STATUS_NONE:
statusString = QLatin1String("NONE");
statusString = QLatin1String("STATUS_NONE");
break;
case FILE_STATUS_EVAL:
statusString = QLatin1String("EVAL");
statusString = QLatin1String("STATUS_EVAL");
break;
case FILE_STATUS_REMOVE:
statusString = QLatin1String("REMOVE");
statusString = QLatin1String("STATUS_REMOVE");
break;
case FILE_STATUS_RENAME:
statusString = QLatin1String("RENAME");
statusString = QLatin1String("STATUS_RENAME");
break;
case FILE_STATUS_NEW:
statusString = QLatin1String("NEW");
statusString = QLatin1String("STATUS_NEW");
break;
case FILE_STATUS_CONFLICT:
statusString = QLatin1String("CONFLICT");
statusString = QLatin1String("STATUS_CONFLICT");
break;
case FILE_STATUS_IGNORE:
statusString = QLatin1String("IGNORE");
statusString = QLatin1String("STATUS_IGNORE");
break;
case FILE_STATUS_SYNC:
statusString = QLatin1String("SYNC");
statusString = QLatin1String("STATUS_SYNC");
break;
case FILE_STATUS_STAT_ERROR:
statusString = QLatin1String("STAT_ERROR");
statusString = QLatin1String("STATUS_STAT_ERROR");
break;
case FILE_STATUS_ERROR:
statusString = QLatin1String("ERROR");
statusString = QLatin1String("STATUS_ERROR");
break;
case FILE_STATUS_UPDATED:
statusString = QLatin1String("UPDATED");
statusString = QLatin1String("STATUS_UPDATED");
break;
default:
qWarning() << "not all SyncFileStatus items checked!";
Q_ASSERT(false);
statusString = QLatin1String("NONE");
statusString = QLatin1String("STATUS_NONE");
}
}
if( ! statusString.isEmpty() ) {
QString message("%1:%2:%3");
message = message.arg("STATUS").arg(statusString).arg(absoluteFilePath);
sendMessage(socket, message);
}
QString message("%1:%2:%3");
message = message.arg("STATUS").arg(statusString).arg(absoluteFilePath);
sendMessage(socket, message);
}
}
+3 -3
Ver Arquivo
@@ -34,10 +34,10 @@ public:
virtual ~SocketApi();
private slots:
void slotNewConnection();
void onNewConnection();
void onLostConnection();
void slotReadSocket();
void slotSyncStateChanged(const QString&);
void onReadyRead();
void onSyncStateChanged(const QString&);
private:
void sendMessage(QLocalSocket* socket, const QString& message);
+35 -304
Ver Arquivo
@@ -15,14 +15,13 @@
#include "mirall/syncengine.h"
#include "mirall/account.h"
#include "mirall/mirallconfigfile.h"
#include "mirall/theme.h"
#include "mirall/logger.h"
#include "owncloudpropagator.h"
#include "syncjournaldb.h"
#include "syncjournalfilerecord.h"
#include "creds/abstractcredentials.h"
#include "csync_util.h"
#include "csync_private.h"
#ifdef Q_OS_WIN
#include <windows.h>
@@ -64,9 +63,9 @@ SyncEngine::SyncEngine(CSYNC *ctx, const QString& localPath, const QString& remo
, _journal(journal)
, _hasNoneFiles(false)
, _hasRemoveFile(false)
, _uploadLimit(0)
, _downloadLimit(0)
, _anotherSyncNeeded(false)
, _uploadLimit(0)
{
qRegisterMetaType<SyncFileItem>("SyncFileItem");
qRegisterMetaType<SyncFileItem::Status>("SyncFileItem::Status");
@@ -243,8 +242,7 @@ bool SyncEngine::checkBlacklisting( SyncFileItem *item )
if( re ) {
qDebug() << "Item is on blacklist: " << entry._file << "retries:" << entry._retryCount;
item->_instruction = CSYNC_INSTRUCTION_ERROR;
item->_status = SyncFileItem::FileIgnored;
item->_instruction = CSYNC_INSTRUCTION_IGNORE;
item->_errorString = tr("The item is not synced because of previous errors: %1").arg(entry._errorString);
}
}
@@ -265,44 +263,16 @@ int SyncEngine::treewalkRemote( TREE_WALK_FILE* file, void *data )
int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
{
if( ! file ) return -1;
QString fileUtf8 = QString::fromUtf8( file->path );
// Gets a default-contructed SyncFileItem or the one from the first walk (=local walk)
SyncFileItem item = _syncItemMap.value(fileUtf8);
item._file = fileUtf8;
SyncFileItem item;
item._file = QString::fromUtf8( file->path );
item._originalFile = item._file;
if (item._instruction == CSYNC_INSTRUCTION_NONE) {
item._instruction = file->instruction;
item._modtime = file->modtime;
} else {
if (file->instruction != CSYNC_INSTRUCTION_NONE) {
Q_ASSERT(!"Instructions are both unequal NONE");
}
}
if (file->file_id && strlen(file->file_id) > 0) {
item._fileId = file->file_id;
}
if (file->directDownloadUrl) {
item._directDownloadUrl = QString::fromUtf8( file->directDownloadUrl );
}
if (file->directDownloadCookies) {
item._directDownloadCookies = QString::fromUtf8( file->directDownloadCookies );
}
if (file->remotePerm && file->remotePerm[0]) {
item._remotePerm = QByteArray(file->remotePerm);
}
item._should_update_etag = item._should_update_etag || file->should_update_etag;
item._instruction = file->instruction;
item._direction = SyncFileItem::None;
item._fileId = file->file_id;
// record the seen files to be able to clean the journal later
_seenFiles.insert(item._file);
if (remote && file->remotePerm && file->remotePerm[0]) {
_remotePerms[item._file] = file->remotePerm;
}
switch(file->error_status) {
case CSYNC_STATUS_OK:
break;
@@ -323,17 +293,14 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
Q_ASSERT("Non handled error-status");
/* No error string */
}
item._isDirectory = file->type == CSYNC_FTW_TYPE_DIR;
// The etag is already set in the previous sync phases somewhere. Maybe we should remove it there
// and do it here so we have a consistent state about which tree stores information from which source.
item._isDirectory = file->type == CSYNC_FTW_TYPE_DIR;
item._modtime = file->modtime;
item._etag = file->etag;
item._size = file->size;
item._inode = file->inode;
if (!remote) {
item._inode = file->inode;
}
item._should_update_etag = file->should_update_etag;
switch( file->type ) {
case CSYNC_FTW_TYPE_DIR:
item._type = SyncFileItem::Directory;
@@ -351,19 +318,15 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
SyncFileItem::Direction dir;
int re = 0;
switch(file->instruction) {
case CSYNC_INSTRUCTION_NONE:
if (file->should_update_etag && !item._isDirectory) {
// Update the database now already (new fileid or etag or remotePerm)
// Those are files that were detected as "resolved conflict".
// They should have been a conflict because they both were new, or both
// had their local mtime or remote etag modified, but the size and mtime
// is the same on the server. This typically happen when the database is removed.
// Nothing will be done for those file, but we still need to update the database.
// Update the database now already (new fileid or etag)
_journal->setFileRecord(SyncJournalFileRecord(item, _localPath + item._file));
item._should_update_etag = false;
}
if (item._isDirectory && (remote || file->should_update_etag)) {
if (item._isDirectory && remote) {
// Because we want still to update etags of directories
dir = SyncFileItem::None;
} else {
@@ -428,8 +391,7 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
item.log._other_modtime = file->other.modtime;
item.log._other_size = file->other.size;
_syncItemMap.insert(fileUtf8, item);
_syncedItems.append(item);
emit syncItemDiscovered(item);
return re;
}
@@ -464,19 +426,6 @@ void SyncEngine::handleSyncError(CSYNC *ctx, const char *state) {
void SyncEngine::startSync()
{
if (_journal->exists()) {
QVector< SyncJournalDb::PollInfo > pollInfos = _journal->getPollInfos();
if (!pollInfos.isEmpty()) {
qDebug() << "Finish Poll jobs before starting a sync";
CleanupPollsJob *job = new CleanupPollsJob(pollInfos, AccountManager::instance()->account(),
_journal, _localPath, this);
connect(job, SIGNAL(finished()), this, SLOT(startSync()));
connect(job, SIGNAL(aborted(QString)), this, SLOT(slotCleanPollsJobAborted(QString)));
job->start();
return;
}
}
Q_ASSERT(!_syncRunning);
_syncRunning = true;
@@ -484,15 +433,7 @@ void SyncEngine::startSync()
qDebug() << "XXXXXXXXXXXXXXXX FAIL: do not have csync_ctx!";
}
if (!QDir(_localPath).exists()) {
// No _tr, it should only occur in non-mirall
emit csyncError("Unable to find local sync directory.");
finalize();
return;
}
_syncedItems.clear();
_syncItemMap.clear();
_needsUpdate = false;
csync_resume(_csync_ctx);
@@ -530,6 +471,7 @@ void SyncEngine::startSync()
}
}
csync_set_module_property(_csync_ctx, "csync_context", _csync_ctx);
csync_set_userdata(_csync_ctx, this);
// TODO: This should be a part of this method, but we don't have
// any way to get "session_key" module property from csync. Had we
@@ -582,7 +524,6 @@ void SyncEngine::slotUpdateFinished(int updateResult)
handleSyncError(_csync_ctx, "csync_reconcile");
return;
}
_stopWatch.addLapTime(QLatin1String("Reconcile Finished"));
_progressInfo = Progress::Info();
@@ -600,26 +541,12 @@ void SyncEngine::slotUpdateFinished(int updateResult)
qDebug() << "Error in remote treewalk.";
}
if (_csync_ctx->remote.root_perms) {
_remotePerms[QLatin1String("")] = _csync_ctx->remote.root_perms;
qDebug() << "Permissions of the root folder: " << _remotePerms[QLatin1String("")];
}
// The map was used for merging trees, convert it to a list:
_syncedItems = _syncItemMap.values().toVector();
// Adjust the paths for the renames.
for (SyncFileItemVector::iterator it = _syncedItems.begin();
it != _syncedItems.end(); ++it) {
it->_file = adjustRenamedPath(it->_file);
}
// Sort items per destination
std::sort(_syncedItems.begin(), _syncedItems.end());
// make sure everything is allowed
checkForPermission();
// Sanity check
if (!_journal->isConnected()) {
qDebug() << "Bailing out, DB failure";
@@ -660,27 +587,31 @@ void SyncEngine::slotUpdateFinished(int updateResult)
connect(_propagator.data(), SIGNAL(adjustTotalTransmissionSize(qint64)), this, SLOT(slotAdjustTotalTransmissionSize(qint64)));
connect(_propagator.data(), SIGNAL(finished()), this, SLOT(slotFinished()), Qt::QueuedConnection);
// apply the network limits to the propagator
setNetworkLimits(_uploadLimit, _downloadLimit);
setNetworkLimits();
_propagator->start(_syncedItems);
}
void SyncEngine::slotCleanPollsJobAborted(const QString &error)
void SyncEngine::setNetworkLimits()
{
csyncError(error);
finalize();
}
void SyncEngine::setNetworkLimits(int upload, int download)
{
_uploadLimit = upload;
_downloadLimit = download;
MirallConfigFile cfg;
if( !_propagator ) return;
_propagator->_uploadLimit = upload;
_propagator->_downloadLimit = download;
int downloadLimit = 0;
if (cfg.useDownloadLimit()) {
downloadLimit = cfg.downloadLimit() * 1000;
}
_propagator->_downloadLimit = downloadLimit;
int uploadLimit = -75; // 75%
int useUpLimit = cfg.useUploadLimit();
if ( useUpLimit >= 1) {
uploadLimit = cfg.uploadLimit() * 1000;
} else if (useUpLimit == 0) {
uploadLimit = 0;
}
_propagator->_uploadLimit = uploadLimit;
int propDownloadLimit = _propagator->_downloadLimit
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
@@ -728,8 +659,6 @@ void SyncEngine::slotJobCompleted(const SyncFileItem &item)
void SyncEngine::slotFinished()
{
_anotherSyncNeeded = _anotherSyncNeeded || _propagator->_anotherSyncNeeded;
// emit the treewalk results.
if( ! _journal->postSyncCleanup( _seenFiles ) ) {
qDebug() << "Cleaning of synced ";
@@ -779,204 +708,6 @@ QString SyncEngine::adjustRenamedPath(const QString& original)
return original;
}
void SyncEngine::checkForPermission()
{
for (SyncFileItemVector::iterator it = _syncedItems.begin(); it != _syncedItems.end(); ++it) {
if (it->_direction != SyncFileItem::Up) {
// Currently we only check server-side permissions
continue;
}
switch(it->_instruction) {
case CSYNC_INSTRUCTION_NEW: {
int slashPos = it->_file.lastIndexOf('/');
QString parentDir = slashPos <= 0 ? "" : it->_file.mid(0, slashPos);
const QByteArray perms = getPermissions(parentDir);
if (perms.isNull()) {
// No permissions set
break;
} else if (it->_isDirectory && !perms.contains("K")) {
qDebug() << "checkForPermission: ERROR" << it->_file;
it->_instruction = CSYNC_INSTRUCTION_ERROR;
it->_status = SyncFileItem::NormalError;
it->_errorString = tr("Not allowed because you don't have permission to add sub-directories in that directory");
const QString path = it->_file + QLatin1Char('/');
for (SyncFileItemVector::iterator it_next = it + 1; it_next != _syncedItems.end() && it_next->_file.startsWith(path); ++it_next) {
it = it_next;
it->_instruction = CSYNC_INSTRUCTION_ERROR;
it->_status = SyncFileItem::NormalError;
it->_errorString = tr("Not allowed because you don't have permission to add parent directory");
}
} else if (!it->_isDirectory && !perms.contains("C")) {
qDebug() << "checkForPermission: ERROR" << it->_file;
it->_instruction = CSYNC_INSTRUCTION_ERROR;
it->_status = SyncFileItem::NormalError;
it->_errorString = tr("Not allowed because you don't have permission to add files in that directory");
}
break;
}
case CSYNC_INSTRUCTION_SYNC: {
const QByteArray perms = getPermissions(it->_file);
if (perms.isNull()) {
// No permissions set
break;
} if (!it->_isDirectory && !perms.contains("W")) {
qDebug() << "checkForPermission: RESTORING" << it->_file;
it->_should_update_etag = true;
it->_instruction = CSYNC_INSTRUCTION_CONFLICT;
it->_direction = SyncFileItem::Down;
it->_isRestoration = true;
// take the things to write to the db from the "other" node (i.e: info from server)
// ^^ FIXME This might not be needed anymore since we merge the info in treewalkFile
it->_modtime = it->log._other_modtime;
it->_fileId = it->log._other_fileId;
it->_etag = it->log._other_etag;
it->_errorString = tr("Not allowed to upload this file because it is read-only on the server, restoring");
continue;
}
break;
}
case CSYNC_INSTRUCTION_REMOVE: {
const QByteArray perms = getPermissions(it->_file);
if (perms.isNull()) {
// No permissions set
break;
} if (!perms.contains("D")) {
qDebug() << "checkForPermission: RESTORING" << it->_file;
it->_should_update_etag = true;
it->_instruction = CSYNC_INSTRUCTION_NEW;
it->_direction = SyncFileItem::Down;
it->_isRestoration = true;
it->_errorString = tr("Not allowed to remove, restoring");
if (it->_isDirectory) {
// restore all sub items
const QString path = it->_file + QLatin1Char('/');
for (SyncFileItemVector::iterator it_next = it + 1;
it_next != _syncedItems.end() && it_next->_file.startsWith(path); ++it_next) {
it = it_next;
if (it->_instruction != CSYNC_INSTRUCTION_REMOVE) {
qWarning() << "non-removed job within a removed directory"
<< it->_file << it->_instruction;
continue;
}
qDebug() << "checkForPermission: RESTORING" << it->_file;
it->_should_update_etag = true;
it->_instruction = CSYNC_INSTRUCTION_NEW;
it->_direction = SyncFileItem::Down;
it->_isRestoration = true;
it->_errorString = tr("Not allowed to remove, restoring");
}
}
}
break;
}
case CSYNC_INSTRUCTION_RENAME: {
int slashPos = it->_renameTarget.lastIndexOf('/');
const QString parentDir = slashPos <= 0 ? "" : it->_renameTarget.mid(0, slashPos);
const QByteArray destPerms = getPermissions(parentDir);
const QByteArray filePerms = getPermissions(it->_file);
//true when it is just a rename in the same directory. (not a move)
bool isRename = it->_file.startsWith(parentDir) && it->_file.lastIndexOf('/') == slashPos;
// Check if we are allowed to move to the destination.
bool destinationOK = true;
if (isRename || destPerms.isNull()) {
// no need to check for the destination dir permission
destinationOK = true;
} else if (it->_isDirectory && !destPerms.contains("K")) {
destinationOK = false;
} else if (!it->_isDirectory && !destPerms.contains("C")) {
destinationOK = false;
}
// check if we are allowed to move from the source
bool sourceOK = true;
if (!filePerms.isNull()
&& ((isRename && !filePerms.contains("N"))
|| (!isRename && !filePerms.contains("V")))) {
// We are not allowed to move or rename this file
sourceOK = false;
if (filePerms.contains("D") && destinationOK) {
// but we are allowed to delete it
// TODO! simulate delete & upload
}
}
#if 0 /* We don't like the idea of renaming behind user's back, as the user may be working with the files */
if (!sourceOK && !destinationOK) {
// Both the source and the destination won't allow move. Move back to the original
std::swap(it->_file, it->_renameTarget);
it->_direction = SyncFileItem::Down;
it->_errorString = tr("Move not allowed, item restored");
it->_isRestoration = true;
qDebug() << "checkForPermission: MOVING BACK" << it->_file;
} else
#endif
if (!sourceOK || !destinationOK) {
// One of them is not possible, just throw an error
it->_instruction = CSYNC_INSTRUCTION_ERROR;
it->_status = SyncFileItem::NormalError;
const QString errorString = tr("Move not allowed because %1 is read-only").arg(
sourceOK ? tr("the destination") : tr("the source"));
it->_errorString = errorString;
qDebug() << "checkForPermission: ERROR MOVING" << it->_file << errorString;
// Avoid a rename on next sync:
// TODO: do the resolution now already so we don't need two sync
// At this point we would need to go back to the propagate phase on both remote to take
// the decision.
_journal->avoidRenamesOnNextSync(it->_file);
_anotherSyncNeeded = true;
if (it->_isDirectory) {
const QString path = it->_renameTarget + QLatin1Char('/');
for (SyncFileItemVector::iterator it_next = it + 1;
it_next != _syncedItems.end() && it_next->destination().startsWith(path); ++it_next) {
it = it_next;
it->_instruction = CSYNC_INSTRUCTION_ERROR;
it->_status = SyncFileItem::NormalError;
it->_errorString = errorString;
qDebug() << "checkForPermission: ERROR MOVING" << it->_file;
}
}
}
break;
}
default:
break;
}
}
}
QByteArray SyncEngine::getPermissions(const QString& file) const
{
static bool isTest = qgetenv("OWNCLOUD_TEST_PERMISSIONS").toInt();
if (isTest) {
QRegExp rx("_PERM_([^_]*)_[^/]*$");
if (rx.indexIn(file) != -1) {
return rx.cap(1).toLatin1();
}
}
return _remotePerms.value(file);
}
void SyncEngine::abort()
{
csync_request_abort(_csync_ctx);
+4 -21
Ver Arquivo
@@ -22,7 +22,6 @@
#include <QThread>
#include <QString>
#include <QSet>
#include <QMap>
#include <qelapsedtimer.h>
#include <csync.h>
@@ -56,16 +55,13 @@ public:
static QString csyncErrorToString( CSYNC_STATUS);
Q_INVOKABLE void startSync();
void setNetworkLimits(int upload, int download);
Q_INVOKABLE void setNetworkLimits();
/* Abort the sync. Called from the main thread */
void abort();
Utility::StopWatch &stopWatch() { return _stopWatch; }
/* Return true if we detected that another sync is needed to complete the sync */
bool isAnotherSyncNeeded() { return _anotherSyncNeeded; }
signals:
void csyncError( const QString& );
void csyncUnavailable();
@@ -97,7 +93,6 @@ private slots:
void slotProgress(const SyncFileItem& item, quint64 curent);
void slotAdjustTotalTransmissionSize(qint64 change);
void slotUpdateFinished(int updateResult);
void slotCleanPollsJobAborted(const QString &error);
private:
void handleSyncError(CSYNC *ctx, const char *state);
@@ -111,7 +106,6 @@ private:
void finalize();
static bool _syncRunning; //true when one sync is running somewhere (for debugging)
QMap<QString, SyncFileItem> _syncItemMap;
SyncFileItemVector _syncedItems;
CSYNC *_csync_ctx;
@@ -133,25 +127,14 @@ private:
QHash<QString, QString> _renamedFolders;
QString adjustRenamedPath(const QString &original);
/**
* check if we are allowed to propagate everything, and if we are not, adjust the instructions
* to recover
*/
void checkForPermission();
QByteArray getPermissions(const QString& file) const;
bool _hasNoneFiles; // true if there is at least one file with instruction NONE
bool _hasRemoveFile; // true if there is at leasr one file with instruction REMOVE
int _uploadLimit;
int _downloadLimit;
// hash containing the permissions on the remote directory
QHash<QString, QByteArray> _remotePerms;
bool _anotherSyncNeeded;
int _uploadLimit;
};
class UpdateJob : public QObject {
Q_OBJECT
CSYNC *_csync_ctx;
@@ -167,7 +150,7 @@ class UpdateJob : public QObject {
}
public:
explicit UpdateJob(CSYNC *ctx, QObject* parent = 0)
: QObject(parent), _csync_ctx(ctx) {
: QObject(parent), _csync_ctx(ctx) {
// We need to forward the log property as csync uses thread local
// and updates run in another thread
_log_callback = csync_get_log_callback();
+3 -12
Ver Arquivo
@@ -46,14 +46,13 @@ public:
Success, ///< The file was properly synced
Conflict, ///< The file was properly synced, but a conflict was created
FileIgnored, ///< The file is in the ignored list
Restoration ///< The file was restored because what should have been done was not allowed
FileIgnored ///< The file is in the ignored list
};
SyncFileItem() : _type(UnknownType), _direction(None), _isDirectory(false),
_instruction(CSYNC_INSTRUCTION_NONE), _modtime(0),
_size(0), _inode(0), _should_update_etag(false), _blacklistedInDb(false),
_status(NoStatus), _httpErrorCode(0), _requestDuration(0), _isRestoration(false) {}
_status(NoStatus), _httpErrorCode(0), _requestDuration(0) {}
friend bool operator==(const SyncFileItem& item1, const SyncFileItem& item2) {
return item1._file == item2._file;
@@ -65,10 +64,7 @@ public:
}
QString destination() const {
if (!_renameTarget.isEmpty()) {
return _renameTarget;
}
return _file;
return _instruction == CSYNC_INSTRUCTION_RENAME ? _renameTarget : _file;
}
bool isEmpty() const {
@@ -91,9 +87,6 @@ public:
quint64 _inode;
bool _should_update_etag;
QByteArray _fileId;
QByteArray _remotePerm;
QString _directDownloadUrl;
QString _directDownloadCookies;
bool _blacklistedInDb;
// Variables usefull to report to the user
@@ -102,7 +95,6 @@ public:
int _httpErrorCode;
QString _responseTimeStamp;
quint64 _requestDuration;
bool _isRestoration; // The original operation was forbidden, and this is a restoration
struct {
quint64 _size;
@@ -114,7 +106,6 @@ public:
time_t _other_modtime;
QByteArray _other_etag;
QByteArray _other_fileId;
QByteArray _other_remotePerm;
enum csync_instructions_e _other_instruction;
} log;
};
+24 -119
Ver Arquivo
@@ -146,8 +146,6 @@ bool SyncJournalDb::checkConnect()
"modtime INTEGER(8),"
"type INTEGER,"
"md5 VARCHAR(32)," /* This is the etag. Called md5 for compatibility */
// updateDatabaseStructure() will add a fileid column
// updateDatabaseStructure() will add a remotePerm column
"PRIMARY KEY(phash)"
");");
@@ -195,14 +193,6 @@ bool SyncJournalDb::checkConnect()
return sqlFail("Create table blacklist", createQuery);
}
createQuery.prepare("CREATE TABLE IF NOT EXISTS poll("
"path VARCHAR(4096),"
"modtime INTEGER(8),"
"pollpath VARCHAR(4096));");
if (!createQuery.exec()) {
return sqlFail("Create table poll", createQuery);
}
createQuery.prepare("CREATE TABLE IF NOT EXISTS version("
"major INTEGER(8),"
"minor INTEGER(8),"
@@ -237,13 +227,13 @@ bool SyncJournalDb::checkConnect()
bool rc = updateDatabaseStructure();
if( rc ) {
_getFileRecordQuery.reset(new QSqlQuery(_db));
_getFileRecordQuery->prepare("SELECT path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm FROM "
_getFileRecordQuery->prepare("SELECT path, inode, uid, gid, mode, modtime, type, md5, fileid FROM "
"metadata WHERE phash=:ph" );
_setFileRecordQuery.reset(new QSqlQuery(_db) );
_setFileRecordQuery->prepare("INSERT OR REPLACE INTO metadata "
"(phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm) "
"VALUES ( ? , ?, ? , ? , ? , ? , ?, ? , ? , ?, ?, ? )" );
"(phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid) "
"VALUES ( ? , ?, ? , ? , ? , ? , ?, ? , ? , ?, ? )" );
_getDownloadInfoQuery.reset(new QSqlQuery(_db) );
_getDownloadInfoQuery->prepare( "SELECT tmpfile, etag, errorcount FROM "
@@ -305,7 +295,6 @@ void SyncJournalDb::close()
_db.close();
_db = QSqlDatabase(); // avoid the warning QSqlDatabasePrivate::removeDatabase: connection [...] still in use
QSqlDatabase::removeDatabase(_dbFile);
_avoidReadFromDbOnNextSyncFilter.clear();
}
@@ -329,13 +318,6 @@ bool SyncJournalDb::updateDatabaseStructure()
commitInternal("update database structure");
}
if( columns.indexOf(QLatin1String("remotePerm")) == -1 ) {
QSqlQuery query(_db);
query.prepare("ALTER TABLE metadata ADD COLUMN remotePerm VARCHAR(128);");
re = query.exec();
commitInternal("update database structure (remotePerm");
}
return re;
}
@@ -381,47 +363,33 @@ qint64 SyncJournalDb::getPHash(const QString& file) const
return h;
}
bool SyncJournalDb::setFileRecord( const SyncJournalFileRecord& _record )
bool SyncJournalDb::setFileRecord( const SyncJournalFileRecord& record )
{
SyncJournalFileRecord record = _record;
QMutexLocker locker(&_mutex);
if (!_avoidReadFromDbOnNextSyncFilter.isEmpty()) {
// If we are a directory that should not be read from db next time, don't write the etag
QString prefix = record._path + "/";
foreach(const QString &it, _avoidReadFromDbOnNextSyncFilter) {
if (it.startsWith(prefix)) {
qDebug() << "Filtered writing the etag of" << prefix << "because it is a prefix of" << it;
record._etag = "_invalid_";
break;
}
}
}
qlonglong phash = getPHash(record._path);
if( checkConnect() ) {
QByteArray arr = record._path.toUtf8();
int plen = arr.length();
// _setFileRecordQuery->prepare("INSERT OR REPLACE INTO metadata "
// "(phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid) "
// "VALUES ( ? , ?, ? , ? , ? , ? , ?, ? , ? , ?, ? )" );
QString etag( record._etag );
if( etag.isEmpty() ) etag = "";
QString fileId( record._fileId);
if( fileId.isEmpty() ) fileId = "";
QString remotePerm (record._remotePerm);
if (remotePerm.isEmpty()) remotePerm = QString(); // have NULL in DB (vs empty)
_setFileRecordQuery->bindValue(0, QString::number(phash));
_setFileRecordQuery->bindValue(1, plen);
_setFileRecordQuery->bindValue(2, record._path );
_setFileRecordQuery->bindValue(3, record._inode );
_setFileRecordQuery->bindValue(4, 0 ); // uid Not used
_setFileRecordQuery->bindValue(5, 0 ); // gid Not used
_setFileRecordQuery->bindValue(4, record._uid );
_setFileRecordQuery->bindValue(5, record._gid );
_setFileRecordQuery->bindValue(6, record._mode );
_setFileRecordQuery->bindValue(7, QString::number(Utility::qDateTimeToTime_t(record._modtime)));
_setFileRecordQuery->bindValue(8, QString::number(record._type) );
_setFileRecordQuery->bindValue(9, etag );
_setFileRecordQuery->bindValue(10, fileId );
_setFileRecordQuery->bindValue(11, remotePerm );
if( !_setFileRecordQuery->exec() ) {
qWarning() << "Error SQL statement setFileRecord: " << _setFileRecordQuery->lastQuery() << " :"
@@ -430,9 +398,9 @@ bool SyncJournalDb::setFileRecord( const SyncJournalFileRecord& _record )
}
qDebug() << _setFileRecordQuery->lastQuery() << phash << plen << record._path << record._inode
<< record._mode
<< record._uid << record._gid << record._mode
<< QString::number(Utility::qDateTimeToTime_t(record._modtime)) << QString::number(record._type)
<< record._etag << record._fileId << record._remotePerm;
<< record._etag << record._fileId;
_setFileRecordQuery->finish();
return true;
@@ -487,6 +455,12 @@ SyncJournalFileRecord SyncJournalDb::getFileRecord( const QString& filename )
qlonglong phash = getPHash( filename );
SyncJournalFileRecord rec;
/*
CREATE TABLE "metadata"(phash INTEGER(8),pathlen INTEGER,path VARCHAR(4096),inode INTEGER,uid INTEGER,gid INTEGER,mode INTEGER,modtime INTEGER(8),type INTEGER,md5 VARCHAR(32),PRIMARY KEY(phash));
CREATE INDEX metadata_inode ON metadata(inode);
CREATE INDEX metadata_phash ON metadata(phash);
*/
if( checkConnect() ) {
_getFileRecordQuery->bindValue(":ph", QString::number(phash));
@@ -500,19 +474,18 @@ SyncJournalFileRecord SyncJournalDb::getFileRecord( const QString& filename )
bool ok;
rec._path = _getFileRecordQuery->value(0).toString();
rec._inode = _getFileRecordQuery->value(1).toInt(&ok);
//rec._uid = _getFileRecordQuery->value(2).toInt(&ok); Not Used
//rec._gid = _getFileRecordQuery->value(3).toInt(&ok); Not Used
rec._uid = _getFileRecordQuery->value(2).toInt(&ok);
rec._gid = _getFileRecordQuery->value(3).toInt(&ok);
rec._mode = _getFileRecordQuery->value(4).toInt(&ok);
rec._modtime = Utility::qDateTimeFromTime_t(_getFileRecordQuery->value(5).toLongLong(&ok));
rec._type = _getFileRecordQuery->value(6).toInt(&ok);
rec._etag = _getFileRecordQuery->value(7).toString();
rec._fileId = _getFileRecordQuery->value(8).toString();
rec._remotePerm = _getFileRecordQuery->value(9).toByteArray();
_getFileRecordQuery->finish();
} else {
QString err = _getFileRecordQuery->lastError().text();
qDebug() << "No journal entry found for " << filename;
qDebug() << "Can not query " << _getFileRecordQuery->lastQuery() << ", Error:" << err;
}
}
return rec;
@@ -843,66 +816,6 @@ void SyncJournalDb::updateBlacklistEntry( const SyncJournalBlacklistRecord& item
}
QVector< SyncJournalDb::PollInfo > SyncJournalDb::getPollInfos()
{
QMutexLocker locker(&_mutex);
QVector< SyncJournalDb::PollInfo > res;
if( !checkConnect() )
return res;
QSqlQuery query("SELECT path, modtime, pollpath FROM poll",_db);
if (!query.exec()) {
QString err = query.lastError().text();
qDebug() << "Database error :" << query.lastQuery() << ", Error:" << err;
return res;
}
while( query.next() ) {
PollInfo info;
info._file = query.value(0).toString();
info._modtime = query.value(1).toLongLong();
info._url = query.value(2).toString();
res.append(info);
qDebug() << "§§§§§§§§§§§§§§§§" << info._file << info._url;
}
qDebug() << "§§§§§§§§§-*-*-*§§§§§§§" << res.count();
query.finish();
return res;
}
void SyncJournalDb::setPollInfo(const SyncJournalDb::PollInfo& info)
{
QMutexLocker locker(&_mutex);
if( !checkConnect() ) {
return;
}
if (info._url.isEmpty()) {
QSqlQuery query("DELETE FROM poll WHERE path=?", _db);
query.bindValue(0, info._file);
if( !query.exec() ) {
qDebug() << "SQL error in setPollInfo: "<< query.lastError().text();
} else {
qDebug() << query.executedQuery() << info._file;
}
} else {
QSqlQuery query("INSERT OR REPLACE INTO poll (path, modtime, pollpath) VALUES( ? , ? , ? )", _db);
query.bindValue(0, info._file);
query.bindValue(1, QString::number(info._modtime));
query.bindValue(2, info._url);
if( !query.exec() ) {
qDebug() << "SQL error in setPollInfo: "<< query.lastError().text();
} else {
qDebug() << query.executedQuery() << info._file << info._url;
}
}
}
void SyncJournalDb::avoidRenamesOnNextSync(const QString& path)
{
QMutexLocker locker(&_mutex);
@@ -916,15 +829,10 @@ void SyncJournalDb::avoidRenamesOnNextSync(const QString& path)
query.bindValue(0, path);
query.bindValue(1, path);
if( !query.exec() ) {
qDebug() << Q_FUNC_INFO << "SQL error in avoidRenamesOnNextSync: "<< query.lastError().text();
qDebug() << "SQL error in avoidRenamesOnNextSync: "<< query.lastError().text();
} else {
qDebug() << Q_FUNC_INFO << query.executedQuery() << path << "(" << query.numRowsAffected() << " rows)";
qDebug() << query.executedQuery() << path;
}
// We also need to remove the ETags so the update phase refreshes the directory paths
// on the next sync
locker.unlock();
avoidReadFromDbOnNextSync(path);
}
void SyncJournalDb::avoidReadFromDbOnNextSync(const QString& fileName)
@@ -944,13 +852,10 @@ void SyncJournalDb::avoidReadFromDbOnNextSync(const QString& fileName)
query.prepare("UPDATE metadata SET md5='_invalid_' WHERE ? LIKE(path||'/%') AND type == 2"); // CSYNC_FTW_TYPE_DIR == 2
query.bindValue(0, fileName);
if( !query.exec() ) {
qDebug() << Q_FUNC_INFO << "SQL error in avoidRenamesOnNextSync: "<< query.lastError().text();
qDebug() << "SQL error in avoidRenamesOnNextSync: "<< query.lastError().text();
} else {
qDebug() << Q_FUNC_INFO << query.executedQuery() << fileName << "(" << query.numRowsAffected() << " rows)";
qDebug() << query.executedQuery() << fileName;
}
// Prevent future overwrite of the etag for this sync
_avoidReadFromDbOnNextSyncFilter.append(fileName);
}
void SyncJournalDb::commit(const QString& context, bool startTrans)
+7 -14
Ver Arquivo
@@ -66,20 +66,12 @@ public:
bool _valid;
};
struct PollInfo {
QString _file;
QString _url;
time_t _modtime;
};
DownloadInfo getDownloadInfo(const QString &file);
void setDownloadInfo(const QString &file, const DownloadInfo &i);
UploadInfo getUploadInfo(const QString &file);
void setUploadInfo(const QString &file, const UploadInfo &i);
SyncJournalBlacklistRecord blacklistEntry( const QString& );
void avoidRenamesOnNextSync(const QString &path);
void setPollInfo(const PollInfo &);
QVector<PollInfo> getPollInfos();
/**
* Make sure that on the next sync, filName is not read from the DB but use the PROPFIND to
@@ -107,6 +99,13 @@ public:
*/
bool isUpdateFrom_1_5();
signals:
public slots:
private:
qint64 getPHash(const QString& ) const;
bool updateDatabaseStructure();
@@ -133,12 +132,6 @@ private:
QScopedPointer<QSqlQuery> _deleteFileRecordPhash;
QScopedPointer<QSqlQuery> _deleteFileRecordRecursively;
QScopedPointer<QSqlQuery> _blacklistQuery;
/* This is the list of paths we called avoidReadFromDbOnNextSync on.
* It means that they should not be written to the DB in any case since doing
* that would write the etag and would void the purpose of avoidReadFromDbOnNextSync
*/
QList<QString> _avoidReadFromDbOnNextSyncFilter;
};
} // namespace Mirall
+3 -4
Ver Arquivo
@@ -27,14 +27,14 @@
namespace Mirall {
SyncJournalFileRecord::SyncJournalFileRecord()
:_inode(0), _type(0), _mode(0)
:_inode(0), _type(0), _uid(0), _gid(0), _mode(0)
{
}
SyncJournalFileRecord::SyncJournalFileRecord(const SyncFileItem &item, const QString &localFileName)
: _path(item._file), _modtime(Utility::qDateTimeFromTime_t(item._modtime)),
_type(item._type), _etag(item._etag), _fileId(item._fileId), _remotePerm(item._remotePerm),
_mode(0)
_type(item._type), _etag(item._etag), _fileId(item._fileId),
_uid(0), _gid(0), _mode(0)
{
// use the "old" inode coming with the item for the case where the
// filesystem stat fails. That can happen if the the file was removed
@@ -77,7 +77,6 @@ SyncJournalFileRecord::SyncJournalFileRecord(const SyncFileItem &item, const QSt
_inode = sb.st_ino;
}
#endif
qDebug() << Q_FUNC_INFO << localFileName << "Retrieved inode " << _inode << "(previous item inode: " << item._inode << ")";
}
+6 -3
Ver Arquivo
@@ -31,13 +31,16 @@ public:
return !_path.isEmpty();
}
// query("SELECT path, inode, uid, gid, mode, modtime, type, md5 FROM metadata WHERE phash=:phash");
QString _path;
quint64 _inode;
QDateTime _modtime;
int _type;
QString _etag; // FIXME Why not QByteArray?
QString _fileId; // FIXME Why not QByteArray?
QByteArray _remotePerm;
QString _etag;
QString _fileId;
int _uid;
int _gid;
int _mode;
};
+1 -2
Ver Arquivo
@@ -153,14 +153,13 @@ QIcon Theme::themeIcon( const QString& name, bool sysTray ) const
return icon;
}
#endif
Theme::Theme() :
QObject(0)
,_mono(false)
{
}
#endif
// if this option return true, the client only supports one folder to sync.
// The Add-Button is removed accoringly.
+5 -1
Ver Arquivo
@@ -16,6 +16,7 @@
#include <QDir>
#include <QFileDialog>
#include <QUrl>
#include <QTimer>
#include <QPushButton>
#include <QMessageBox>
@@ -145,9 +146,12 @@ void OwncloudSetupPage::initializePage()
if (Theme::instance()->overrideServerUrl().isEmpty()) {
_ui.leUrl->setFocus();
} else {
setVisible(false);
setCommitPage(true);
validatePage();
setVisible(false);
// because the wizard will call show on us right after this call, we need to hide in the
// next event loop iteration.
QTimer::singleShot(0, this, SLOT(hide()));
}
}
-1
Ver Arquivo
@@ -161,7 +161,6 @@ void OwncloudWizard::slotCurrentPageChanged( int id )
if( id == WizardCommon::Page_ServerSetup ) {
emit clearPendingRequests();
_setupPage->initializePage();
}
if( id == WizardCommon::Page_Result ) {
+2
Ver Arquivo
@@ -55,6 +55,8 @@ private slots:
QCOMPARE( QString::number(st->pathlen), QString::number(13));
QCOMPARE( QString::fromUtf8(st->path), QLatin1String("test2/zu/zuzu") );
QCOMPARE( QString::number(st->inode), QString::number(1709554));
QCOMPARE( QString::number(st->uid), QString::number(0));
QCOMPARE( QString::number(st->gid), QString::number(0));
QCOMPARE( QString::number(st->mode), QString::number(0));
QCOMPARE( QString::number(st->modtime), QString::number(1384415006));
QCOMPARE( QString::number(st->type), QString::number(2));
+37 -37
Ver Arquivo
@@ -260,100 +260,100 @@
<context>
<name>Mirall::Folder</name>
<message>
<location filename="../src/mirall/folder.cpp" line="118"/>
<location filename="../src/mirall/folder.cpp" line="107"/>
<source>Unable to create csync-context</source>
<translation>No s&apos;ha pogut crear el context-csync</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="174"/>
<location filename="../src/mirall/folder.cpp" line="165"/>
<source>Local folder %1 does not exist.</source>
<translation>El fitxer local %1 no existeix.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="177"/>
<location filename="../src/mirall/folder.cpp" line="168"/>
<source>%1 should be a directory but is not.</source>
<translation>%1 hauria de ser una carpeta, però no ho és.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="180"/>
<location filename="../src/mirall/folder.cpp" line="171"/>
<source>%1 is not readable.</source>
<translation>No es pot llegir %1.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="332"/>
<location filename="../src/mirall/folder.cpp" line="323"/>
<source>%1: %2</source>
<translation>%1: %2</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="418"/>
<location filename="../src/mirall/folder.cpp" line="409"/>
<source>%1 and %2 other files have been removed.</source>
<comment>%1 names a file.</comment>
<translation>%1 i %2 altres fitxers s&apos;han esborrat</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="420"/>
<location filename="../src/mirall/folder.cpp" line="411"/>
<source>%1 has been removed.</source>
<comment>%1 names a file.</comment>
<translation>S&apos;ha esborrat &apos;%1&apos;</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="425"/>
<location filename="../src/mirall/folder.cpp" line="416"/>
<source>%1 and %2 other files have been downloaded.</source>
<comment>%1 names a file.</comment>
<translation>%1 i %2 altres fitxers s&apos;han descarregat.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="427"/>
<location filename="../src/mirall/folder.cpp" line="418"/>
<source>%1 has been downloaded.</source>
<comment>%1 names a file.</comment>
<translation>S&apos;ha descarregat %1</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="432"/>
<location filename="../src/mirall/folder.cpp" line="423"/>
<source>%1 and %2 other files have been updated.</source>
<translation>%1 i %2 altres fitxer(s) s&apos;han actualitzat.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="434"/>
<location filename="../src/mirall/folder.cpp" line="425"/>
<source>%1 has been updated.</source>
<comment>%1 names a file.</comment>
<translation>S&apos;ha actualitzat %1</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="439"/>
<location filename="../src/mirall/folder.cpp" line="430"/>
<source>%1 has been renamed to %2 and %3 other files have been renamed.</source>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="441"/>
<location filename="../src/mirall/folder.cpp" line="432"/>
<source>%1 has been renamed to %2.</source>
<comment>%1 and %2 name files.</comment>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="446"/>
<location filename="../src/mirall/folder.cpp" line="437"/>
<source>%1 has been moved to %2 and %3 other files have been moved.</source>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="448"/>
<location filename="../src/mirall/folder.cpp" line="439"/>
<source>%1 has been moved to %2.</source>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="456"/>
<location filename="../src/mirall/folder.cpp" line="447"/>
<source>Sync Activity</source>
<translation>Activitat de sincronització</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="706"/>
<location filename="../src/mirall/folder.cpp" line="697"/>
<source>This sync would remove all the files in the local sync folder '%1'.
If you or your administrator have reset your account on the server, choose &quot;Keep files&quot;. If you want your data to be removed, choose &quot;Remove all files&quot;.</source>
<translation>Aquesta sincronització eliminarà tots els fitxers a la carpeta local de sincronització &apos;%1&apos;.
Si vós o l&apos;administrador heu reinicialitzat el compte en el servidor, escolliu &quot;Mantenir fitxers&quot;. Si voleueliminar les dades, escolliu &quot;Esborra tots els fitxers&quot;.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="709"/>
<location filename="../src/mirall/folder.cpp" line="700"/>
<source>This sync would remove all the files in the sync folder '%1'.
This might be because the folder was silently reconfigured, or that all the file were manually removed.
Are you sure you want to perform this operation?</source>
@@ -362,17 +362,17 @@ Això podria ser perquè la carpeta ha estat reconfigurada silenciosament, o que
Esteu segur que voleu executar aquesta operació?</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="713"/>
<location filename="../src/mirall/folder.cpp" line="704"/>
<source>Remove All Files?</source>
<translation>Esborra tots els fitxers?</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="715"/>
<location filename="../src/mirall/folder.cpp" line="706"/>
<source>Remove all files</source>
<translation>Esborra tots els fitxers</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="716"/>
<location filename="../src/mirall/folder.cpp" line="707"/>
<source>Keep files</source>
<translation>Mantén els fitxers</translation>
</message>
@@ -596,17 +596,17 @@ Esteu segur que voleu executar aquesta operació?</translation>
<context>
<name>Mirall::GETFileJob</name>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="428"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="393"/>
<source>No E-Tag received from server, check Proxy/Gateway</source>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="435"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="400"/>
<source>We received a different E-Tag for resuming. Retrying next time.</source>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="471"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="633"/>
<source>Connection Timeout</source>
<translation type="unfinished"/>
</message>
@@ -1278,7 +1278,7 @@ No és aconsellada usar-la.</translation>
<context>
<name>Mirall::PropagateDownloadFileQNAM</name>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="485"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="443"/>
<source>File %1 can not be downloaded because of a local file name clash!</source>
<translation type="unfinished"/>
</message>
@@ -1336,17 +1336,17 @@ No és aconsellada usar-la.</translation>
<context>
<name>Mirall::PropagateRemoteRename</name>
<message>
<location filename="../src/mirall/propagatorjobs.cpp" line="233"/>
<location filename="../src/mirall/propagatorjobs.cpp" line="242"/>
<source>This folder must not be renamed. It is renamed back to its original name.</source>
<translation>No s&apos;ha de canviar el nom d&apos;aquesta carpeta. Es reanomena de nou amb el seu nom original.</translation>
</message>
<message>
<location filename="../src/mirall/propagatorjobs.cpp" line="235"/>
<location filename="../src/mirall/propagatorjobs.cpp" line="244"/>
<source>This folder must not be renamed. Please name it back to Shared.</source>
<translation>Aquesta carpeta no es pot reanomenar. Reanomeneu-la de nou Shared.</translation>
</message>
<message>
<location filename="../src/mirall/propagatorjobs.cpp" line="250"/>
<location filename="../src/mirall/propagatorjobs.cpp" line="259"/>
<source>The file was renamed but is part of a read only share. The original file was restored.</source>
<translation type="unfinished"/>
</message>
@@ -1378,12 +1378,12 @@ No és aconsellada usar-la.</translation>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="278"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="272"/>
<source>Local file changed during sync.</source>
<translation>El fitxer local ha canviat durant la sincronització.</translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="288"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="282"/>
<source>The server did not acknowledge the last chunk. (No e-tag were present)</source>
<translation type="unfinished"/>
</message>
@@ -1537,12 +1537,12 @@ Proveu de sincronitzar-los de nou.</translation>
<context>
<name>Mirall::ShibbolethCredentials</name>
<message>
<location filename="../src/creds/shibbolethcredentials.cpp" line="267"/>
<location filename="../src/creds/shibbolethcredentials.cpp" line="259"/>
<source>Login Error</source>
<translation>Error d&apos;accés</translation>
</message>
<message>
<location filename="../src/creds/shibbolethcredentials.cpp" line="267"/>
<location filename="../src/creds/shibbolethcredentials.cpp" line="259"/>
<source>You must sign in as user %1</source>
<translation>Cal identificar-se com a usuari %1</translation>
</message>
@@ -1925,27 +1925,27 @@ Proveu de sincronitzar-los de nou.</translation>
<translation>L&apos;element no s&apos;ha sincronitzat degut a errors previs: %1</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="280"/>
<location filename="../src/mirall/syncengine.cpp" line="274"/>
<source>Symbolic links are not supported in syncing.</source>
<translation>La sincronització d&apos;enllaços simbòlics no està implementada.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="283"/>
<location filename="../src/mirall/syncengine.cpp" line="277"/>
<source>File is listed on the ignore list.</source>
<translation>El fitxer està a la llista d&apos;ignorats.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="286"/>
<location filename="../src/mirall/syncengine.cpp" line="280"/>
<source>File contains invalid characters that can not be synced cross platform.</source>
<translation>El fitxer conté caràcters no vàlids que no es poden sincronitzar entre plataformes.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="453"/>
<location filename="../src/mirall/syncengine.cpp" line="448"/>
<source>Unable to initialize a sync journal.</source>
<translation>No es pot inicialitzar un periòdic de sincronització</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="549"/>
<location filename="../src/mirall/syncengine.cpp" line="545"/>
<source>Cannot open the sync journal</source>
<translation>No es pot obrir el diari de sincronització</translation>
</message>
+37 -37
Ver Arquivo
@@ -260,100 +260,100 @@
<context>
<name>Mirall::Folder</name>
<message>
<location filename="../src/mirall/folder.cpp" line="118"/>
<location filename="../src/mirall/folder.cpp" line="107"/>
<source>Unable to create csync-context</source>
<translation>Nepodařilo se vytvořit csync-context</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="174"/>
<location filename="../src/mirall/folder.cpp" line="165"/>
<source>Local folder %1 does not exist.</source>
<translation>Místní složka %1 neexistuje.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="177"/>
<location filename="../src/mirall/folder.cpp" line="168"/>
<source>%1 should be a directory but is not.</source>
<translation>%1 by měl být adresář, ale není.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="180"/>
<location filename="../src/mirall/folder.cpp" line="171"/>
<source>%1 is not readable.</source>
<translation>%1 není čitelný.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="332"/>
<location filename="../src/mirall/folder.cpp" line="323"/>
<source>%1: %2</source>
<translation>%1: %2</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="418"/>
<location filename="../src/mirall/folder.cpp" line="409"/>
<source>%1 and %2 other files have been removed.</source>
<comment>%1 names a file.</comment>
<translation>%1 a %2 dalších souborů bylo odebráno.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="420"/>
<location filename="../src/mirall/folder.cpp" line="411"/>
<source>%1 has been removed.</source>
<comment>%1 names a file.</comment>
<translation>%1 byl odebrán.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="425"/>
<location filename="../src/mirall/folder.cpp" line="416"/>
<source>%1 and %2 other files have been downloaded.</source>
<comment>%1 names a file.</comment>
<translation>%1 a %2 dalších souborů bylo staženo.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="427"/>
<location filename="../src/mirall/folder.cpp" line="418"/>
<source>%1 has been downloaded.</source>
<comment>%1 names a file.</comment>
<translation>%1 byl stažen.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="432"/>
<location filename="../src/mirall/folder.cpp" line="423"/>
<source>%1 and %2 other files have been updated.</source>
<translation>%1 a %2 dalších souborů bylo aktualizováno.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="434"/>
<location filename="../src/mirall/folder.cpp" line="425"/>
<source>%1 has been updated.</source>
<comment>%1 names a file.</comment>
<translation>%1 byl aktualizován.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="439"/>
<location filename="../src/mirall/folder.cpp" line="430"/>
<source>%1 has been renamed to %2 and %3 other files have been renamed.</source>
<translation>%1 byl přejmenován na %2 a %3 dalších souborů bylo přejmenováno.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="441"/>
<location filename="../src/mirall/folder.cpp" line="432"/>
<source>%1 has been renamed to %2.</source>
<comment>%1 and %2 name files.</comment>
<translation>%1 byl přejmenován na %2.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="446"/>
<location filename="../src/mirall/folder.cpp" line="437"/>
<source>%1 has been moved to %2 and %3 other files have been moved.</source>
<translation>%1 byl přesunut do %2 a %3 dalších souborů bylo přesunuto.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="448"/>
<location filename="../src/mirall/folder.cpp" line="439"/>
<source>%1 has been moved to %2.</source>
<translation>%1 byl přemístěn do %2.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="456"/>
<location filename="../src/mirall/folder.cpp" line="447"/>
<source>Sync Activity</source>
<translation>Průběh synchronizace</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="706"/>
<location filename="../src/mirall/folder.cpp" line="697"/>
<source>This sync would remove all the files in the local sync folder '%1'.
If you or your administrator have reset your account on the server, choose &quot;Keep files&quot;. If you want your data to be removed, choose &quot;Remove all files&quot;.</source>
<translation>Tato synchronizace by smazala všechny soubory v místní složce &apos;%1&apos;
Pokud jste vy nebo váš správce zresetovali účet na serveru, zvolte &quot;Ponechat soubory&quot;. Pokud chcete místní data odstranit, zvolte &quot;Odstranit všechny soubory&quot;.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="709"/>
<location filename="../src/mirall/folder.cpp" line="700"/>
<source>This sync would remove all the files in the sync folder '%1'.
This might be because the folder was silently reconfigured, or that all the file were manually removed.
Are you sure you want to perform this operation?</source>
@@ -362,17 +362,17 @@ Toto může být způsobeno změnou v nastavení synchronizace složky nebo tím
Opravdu chcete provést tuto akci?</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="713"/>
<location filename="../src/mirall/folder.cpp" line="704"/>
<source>Remove All Files?</source>
<translation>Odstranit všechny soubory?</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="715"/>
<location filename="../src/mirall/folder.cpp" line="706"/>
<source>Remove all files</source>
<translation>Odstranit všechny soubory</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="716"/>
<location filename="../src/mirall/folder.cpp" line="707"/>
<source>Keep files</source>
<translation>Ponechat soubory</translation>
</message>
@@ -596,17 +596,17 @@ Opravdu chcete provést tuto akci?</translation>
<context>
<name>Mirall::GETFileJob</name>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="428"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="393"/>
<source>No E-Tag received from server, check Proxy/Gateway</source>
<translation>Ze serveru nebyl obdržen E-Tag, zkontrolujte proxy/bránu</translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="435"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="400"/>
<source>We received a different E-Tag for resuming. Retrying next time.</source>
<translation>Obdrželi jsme jiný E-Tag pro pokračování. Zkusím znovu příště.</translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="471"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="633"/>
<source>Connection Timeout</source>
<translation>Spojení Vypršelo</translation>
</message>
@@ -1278,7 +1278,7 @@ Nedoporučuje se jí používat.</translation>
<context>
<name>Mirall::PropagateDownloadFileQNAM</name>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="485"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="443"/>
<source>File %1 can not be downloaded because of a local file name clash!</source>
<translation type="unfinished"/>
</message>
@@ -1336,17 +1336,17 @@ Nedoporučuje se jí používat.</translation>
<context>
<name>Mirall::PropagateRemoteRename</name>
<message>
<location filename="../src/mirall/propagatorjobs.cpp" line="233"/>
<location filename="../src/mirall/propagatorjobs.cpp" line="242"/>
<source>This folder must not be renamed. It is renamed back to its original name.</source>
<translation>Tato složka nemůže být přejmenována. Byl vrácen původní název.</translation>
</message>
<message>
<location filename="../src/mirall/propagatorjobs.cpp" line="235"/>
<location filename="../src/mirall/propagatorjobs.cpp" line="244"/>
<source>This folder must not be renamed. Please name it back to Shared.</source>
<translation>Tato složka nemůže být přejmenována. Přejmenujte prosím zpět na Shared.</translation>
</message>
<message>
<location filename="../src/mirall/propagatorjobs.cpp" line="250"/>
<location filename="../src/mirall/propagatorjobs.cpp" line="259"/>
<source>The file was renamed but is part of a read only share. The original file was restored.</source>
<translation>Soubor byl přejmenován, ale je součástí sdílení pouze pro čtení. Původní soubor byl obnoven.</translation>
</message>
@@ -1378,12 +1378,12 @@ Nedoporučuje se jí používat.</translation>
<translation>Soubor zde byl editován, ale je součástí sdílení pouze pro čtení. Původní soubor byl obnoven a editovaná verze je uložena v konfliktním souboru.</translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="278"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="272"/>
<source>Local file changed during sync.</source>
<translation>Místní soubor byl změněn během synchronizace.</translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="288"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="282"/>
<source>The server did not acknowledge the last chunk. (No e-tag were present)</source>
<translation type="unfinished"/>
</message>
@@ -1538,12 +1538,12 @@ Zkuste provést novou synchronizaci.
<context>
<name>Mirall::ShibbolethCredentials</name>
<message>
<location filename="../src/creds/shibbolethcredentials.cpp" line="267"/>
<location filename="../src/creds/shibbolethcredentials.cpp" line="259"/>
<source>Login Error</source>
<translation>Chyba přihlášení</translation>
</message>
<message>
<location filename="../src/creds/shibbolethcredentials.cpp" line="267"/>
<location filename="../src/creds/shibbolethcredentials.cpp" line="259"/>
<source>You must sign in as user %1</source>
<translation>Musíte se přihlásit jako uživatel %1</translation>
</message>
@@ -1926,27 +1926,27 @@ Zkuste provést novou synchronizaci.
<translation>Položka nebyla synchronizována kvůli předchozí chybě: %1</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="280"/>
<location filename="../src/mirall/syncengine.cpp" line="274"/>
<source>Symbolic links are not supported in syncing.</source>
<translation>Symbolické odkazy nejsou při synchronizaci podporovány.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="283"/>
<location filename="../src/mirall/syncengine.cpp" line="277"/>
<source>File is listed on the ignore list.</source>
<translation>Soubor se nachází na seznamu ignorovaných.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="286"/>
<location filename="../src/mirall/syncengine.cpp" line="280"/>
<source>File contains invalid characters that can not be synced cross platform.</source>
<translation>Soubor obsahuje alespoň jeden neplatný znak, který narušuje synchronizaci v prostředí více platforem.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="453"/>
<location filename="../src/mirall/syncengine.cpp" line="448"/>
<source>Unable to initialize a sync journal.</source>
<translation>Nemohu inicializovat synchronizační žurnál.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="549"/>
<location filename="../src/mirall/syncengine.cpp" line="545"/>
<source>Cannot open the sync journal</source>
<translation>Nelze otevřít synchronizační žurnál</translation>
</message>
+37 -37
Ver Arquivo
@@ -261,100 +261,100 @@ Diese Funktion ist nur für Wartungszwecke gedacht. Es werden keine Dateien entf
<context>
<name>Mirall::Folder</name>
<message>
<location filename="../src/mirall/folder.cpp" line="118"/>
<location filename="../src/mirall/folder.cpp" line="107"/>
<source>Unable to create csync-context</source>
<translation>Kann keinen CSync-Kontext erstellen</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="174"/>
<location filename="../src/mirall/folder.cpp" line="165"/>
<source>Local folder %1 does not exist.</source>
<translation>Lokales Verzeichnis %1 existiert nicht.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="177"/>
<location filename="../src/mirall/folder.cpp" line="168"/>
<source>%1 should be a directory but is not.</source>
<translation>%1 sollte ein Verzeichnis sein, ist es aber nicht.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="180"/>
<location filename="../src/mirall/folder.cpp" line="171"/>
<source>%1 is not readable.</source>
<translation>%1 ist nicht lesbar.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="332"/>
<location filename="../src/mirall/folder.cpp" line="323"/>
<source>%1: %2</source>
<translation>%1: %2</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="418"/>
<location filename="../src/mirall/folder.cpp" line="409"/>
<source>%1 and %2 other files have been removed.</source>
<comment>%1 names a file.</comment>
<translation>%1 und %2 andere Dateien wurden gelöscht.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="420"/>
<location filename="../src/mirall/folder.cpp" line="411"/>
<source>%1 has been removed.</source>
<comment>%1 names a file.</comment>
<translation>%1 wurde gelöscht.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="425"/>
<location filename="../src/mirall/folder.cpp" line="416"/>
<source>%1 and %2 other files have been downloaded.</source>
<comment>%1 names a file.</comment>
<translation>%1 und %2 andere Dateien wurden heruntergeladen.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="427"/>
<location filename="../src/mirall/folder.cpp" line="418"/>
<source>%1 has been downloaded.</source>
<comment>%1 names a file.</comment>
<translation>%1 wurde heruntergeladen.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="432"/>
<location filename="../src/mirall/folder.cpp" line="423"/>
<source>%1 and %2 other files have been updated.</source>
<translation>%1 und %2 andere Dateien wurden aktualisiert.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="434"/>
<location filename="../src/mirall/folder.cpp" line="425"/>
<source>%1 has been updated.</source>
<comment>%1 names a file.</comment>
<translation>%1 wurde aktualisiert.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="439"/>
<location filename="../src/mirall/folder.cpp" line="430"/>
<source>%1 has been renamed to %2 and %3 other files have been renamed.</source>
<translation>%1 wurde in %2 umbenannt und %3 andere Dateien wurden umbenannt.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="441"/>
<location filename="../src/mirall/folder.cpp" line="432"/>
<source>%1 has been renamed to %2.</source>
<comment>%1 and %2 name files.</comment>
<translation>%1 wurde in %2 umbenannt.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="446"/>
<location filename="../src/mirall/folder.cpp" line="437"/>
<source>%1 has been moved to %2 and %3 other files have been moved.</source>
<translation>%1 wurde in %2 verschoben und %3 andere Dateien wurden verschoben.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="448"/>
<location filename="../src/mirall/folder.cpp" line="439"/>
<source>%1 has been moved to %2.</source>
<translation>%1 wurde in %2 verschoben.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="456"/>
<location filename="../src/mirall/folder.cpp" line="447"/>
<source>Sync Activity</source>
<translation>Synchronisierungsaktivität</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="706"/>
<location filename="../src/mirall/folder.cpp" line="697"/>
<source>This sync would remove all the files in the local sync folder '%1'.
If you or your administrator have reset your account on the server, choose &quot;Keep files&quot;. If you want your data to be removed, choose &quot;Remove all files&quot;.</source>
<translation>Dieser Synchronisationsvorgang würde alle Dateien in dem lokalen Ordner &apos;%1&apos; entfernen.
Wenn Sie oder Ihr Administrator Ihr Konto auf dem Server zurückgesetzt haben, wählen Sie &quot;Dateien behalten&quot;. Wenn Sie ihre Daten löschen wollen, wählen Sie &quot;Alle Dateien entfernen&quot;.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="709"/>
<location filename="../src/mirall/folder.cpp" line="700"/>
<source>This sync would remove all the files in the sync folder '%1'.
This might be because the folder was silently reconfigured, or that all the file were manually removed.
Are you sure you want to perform this operation?</source>
@@ -363,17 +363,17 @@ Vielleicht wurde der Ordner neu konfiguriert, oder alle Dateien wurden händisch
Sind Sie sicher, dass sie diese Operation durchführen wollen?</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="713"/>
<location filename="../src/mirall/folder.cpp" line="704"/>
<source>Remove All Files?</source>
<translation>Alle Dateien löschen?</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="715"/>
<location filename="../src/mirall/folder.cpp" line="706"/>
<source>Remove all files</source>
<translation>Lösche alle Dateien</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="716"/>
<location filename="../src/mirall/folder.cpp" line="707"/>
<source>Keep files</source>
<translation>Dateien behalten</translation>
</message>
@@ -597,17 +597,17 @@ Sind Sie sicher, dass sie diese Operation durchführen wollen?</translation>
<context>
<name>Mirall::GETFileJob</name>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="428"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="393"/>
<source>No E-Tag received from server, check Proxy/Gateway</source>
<translation>Kein E-Tag vom Server empfangen, bitte Proxy / Gateway überprüfen</translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="435"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="400"/>
<source>We received a different E-Tag for resuming. Retrying next time.</source>
<translation>Es wurde ein unterschiedlicher E-Tag zum Fortfahren empfangen. Bitte beim nächsten mal nochmal versuchen.</translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="471"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="633"/>
<source>Connection Timeout</source>
<translation>Zeitüberschreitung der Verbindung</translation>
</message>
@@ -1279,7 +1279,7 @@ Es ist nicht ratsam, diese zu benutzen.</translation>
<context>
<name>Mirall::PropagateDownloadFileQNAM</name>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="485"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="443"/>
<source>File %1 can not be downloaded because of a local file name clash!</source>
<translation>Die Datei %1 kann aufgrund eines Konfliktes mit dem lokalen Dateinamen nicht herunter geladen werden!</translation>
</message>
@@ -1337,17 +1337,17 @@ Es ist nicht ratsam, diese zu benutzen.</translation>
<context>
<name>Mirall::PropagateRemoteRename</name>
<message>
<location filename="../src/mirall/propagatorjobs.cpp" line="233"/>
<location filename="../src/mirall/propagatorjobs.cpp" line="242"/>
<source>This folder must not be renamed. It is renamed back to its original name.</source>
<translation>Dieser Ordner muss nicht umbenannt werden. Er wurde zurück zum Originalnamen umbenannt.</translation>
</message>
<message>
<location filename="../src/mirall/propagatorjobs.cpp" line="235"/>
<location filename="../src/mirall/propagatorjobs.cpp" line="244"/>
<source>This folder must not be renamed. Please name it back to Shared.</source>
<translation>Dieser Ordner muss nicht umbenannt werden. Bitte benennen Sie es zurück wie in der Freigabe.</translation>
</message>
<message>
<location filename="../src/mirall/propagatorjobs.cpp" line="250"/>
<location filename="../src/mirall/propagatorjobs.cpp" line="259"/>
<source>The file was renamed but is part of a read only share. The original file was restored.</source>
<translation>Die Datei wurde auf einer Nur-Lese-Freigabe umbenannt. Die Original-Datei wurde wiederhergestellt.</translation>
</message>
@@ -1379,12 +1379,12 @@ Es ist nicht ratsam, diese zu benutzen.</translation>
<translation>Die Datei wurde von einer Nur-Lese-Freigabe lokal bearbeitet. Die Datei wurde wiederhergestellt und Ihre Bearbeitung ist in der Konflikte-Datei.</translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="278"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="272"/>
<source>Local file changed during sync.</source>
<translation>Eine lokale Datei wurde während der Synchronisation geändert.</translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="288"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="282"/>
<source>The server did not acknowledge the last chunk. (No e-tag were present)</source>
<translation>Der Server hat den letzten Block nicht bestätigt. (Der E-Tag war nicht vorhanden)</translation>
</message>
@@ -1538,12 +1538,12 @@ Versuchen Sie diese nochmals zu synchronisieren.</translation>
<context>
<name>Mirall::ShibbolethCredentials</name>
<message>
<location filename="../src/creds/shibbolethcredentials.cpp" line="267"/>
<location filename="../src/creds/shibbolethcredentials.cpp" line="259"/>
<source>Login Error</source>
<translation>Log-In Fehler</translation>
</message>
<message>
<location filename="../src/creds/shibbolethcredentials.cpp" line="267"/>
<location filename="../src/creds/shibbolethcredentials.cpp" line="259"/>
<source>You must sign in as user %1</source>
<translation>Sie müssen sich als %1 einloggen</translation>
</message>
@@ -1926,27 +1926,27 @@ Versuchen Sie diese nochmals zu synchronisieren.</translation>
<translation>Das Element ist aufgrund vorheriger Fehler nicht synchronisiert: %1</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="280"/>
<location filename="../src/mirall/syncengine.cpp" line="274"/>
<source>Symbolic links are not supported in syncing.</source>
<translation>Symbolische Verknüpfungen werden bei der Synchronisation nicht unterstützt.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="283"/>
<location filename="../src/mirall/syncengine.cpp" line="277"/>
<source>File is listed on the ignore list.</source>
<translation>Die Datei ist in der Ignorierliste geführt.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="286"/>
<location filename="../src/mirall/syncengine.cpp" line="280"/>
<source>File contains invalid characters that can not be synced cross platform.</source>
<translation>Die Datei beinhaltet ungültige Zeichen und kann nicht plattformübergreifend synchronisiert werden.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="453"/>
<location filename="../src/mirall/syncengine.cpp" line="448"/>
<source>Unable to initialize a sync journal.</source>
<translation>Synchronisationsbericht konnte nicht initialisiert werden.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="549"/>
<location filename="../src/mirall/syncengine.cpp" line="545"/>
<source>Cannot open the sync journal</source>
<translation>Synchronisationsbericht kann nicht geöffnet werden</translation>
</message>
+37 -37
Ver Arquivo
@@ -260,100 +260,100 @@
<context>
<name>Mirall::Folder</name>
<message>
<location filename="../src/mirall/folder.cpp" line="118"/>
<location filename="../src/mirall/folder.cpp" line="107"/>
<source>Unable to create csync-context</source>
<translation>Αδυναμία δημιουργίας πλαισίου csync</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="174"/>
<location filename="../src/mirall/folder.cpp" line="165"/>
<source>Local folder %1 does not exist.</source>
<translation>Δεν υπάρχει ο τοπικός φάκελος %1.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="177"/>
<location filename="../src/mirall/folder.cpp" line="168"/>
<source>%1 should be a directory but is not.</source>
<translation>%1 επρεπε να ειναι χωρος αποθηκευσης αλλα δεν ειναι.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="180"/>
<location filename="../src/mirall/folder.cpp" line="171"/>
<source>%1 is not readable.</source>
<translation> %1 δεν είναι αναγνώσιμο. </translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="332"/>
<location filename="../src/mirall/folder.cpp" line="323"/>
<source>%1: %2</source>
<translation>%1: %2</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="418"/>
<location filename="../src/mirall/folder.cpp" line="409"/>
<source>%1 and %2 other files have been removed.</source>
<comment>%1 names a file.</comment>
<translation>Το %1 και άλλα %2 αρχεία διαγράφηκαν.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="420"/>
<location filename="../src/mirall/folder.cpp" line="411"/>
<source>%1 has been removed.</source>
<comment>%1 names a file.</comment>
<translation>Το %1 έχει διαγραφεί.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="425"/>
<location filename="../src/mirall/folder.cpp" line="416"/>
<source>%1 and %2 other files have been downloaded.</source>
<comment>%1 names a file.</comment>
<translation>Το αρχείο %1 και άλλα %2 αρχεία έχουν μεταφορτωθεί.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="427"/>
<location filename="../src/mirall/folder.cpp" line="418"/>
<source>%1 has been downloaded.</source>
<comment>%1 names a file.</comment>
<translation>Το αρχείο %1 έχει μεταφορτωθεί.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="432"/>
<location filename="../src/mirall/folder.cpp" line="423"/>
<source>%1 and %2 other files have been updated.</source>
<translation>Το αρχείο %1 και %2 άλλα αρχεία έχουν ενημερωθεί.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="434"/>
<location filename="../src/mirall/folder.cpp" line="425"/>
<source>%1 has been updated.</source>
<comment>%1 names a file.</comment>
<translation>Το αρχείο %1 έχει ενημερωθεί.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="439"/>
<location filename="../src/mirall/folder.cpp" line="430"/>
<source>%1 has been renamed to %2 and %3 other files have been renamed.</source>
<translation>Το αρχείο %1 έχει μετονομαστεί σε %2 και άλλα %3 αρχεία έχουν μετονομαστεί.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="441"/>
<location filename="../src/mirall/folder.cpp" line="432"/>
<source>%1 has been renamed to %2.</source>
<comment>%1 and %2 name files.</comment>
<translation>Το αρχείο %1 έχει μετονομαστεί σε %2</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="446"/>
<location filename="../src/mirall/folder.cpp" line="437"/>
<source>%1 has been moved to %2 and %3 other files have been moved.</source>
<translation>Το αρχείο %1 έχει μετακινηθεί στο %2 και %3 άλλα αρχεία έχουν μετακινηθεί.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="448"/>
<location filename="../src/mirall/folder.cpp" line="439"/>
<source>%1 has been moved to %2.</source>
<translation>Το αρχείο %1 έχει μετακινηθεί στο %2.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="456"/>
<location filename="../src/mirall/folder.cpp" line="447"/>
<source>Sync Activity</source>
<translation>Δραστηριότητα Συγχρονισμού</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="706"/>
<location filename="../src/mirall/folder.cpp" line="697"/>
<source>This sync would remove all the files in the local sync folder '%1'.
If you or your administrator have reset your account on the server, choose &quot;Keep files&quot;. If you want your data to be removed, choose &quot;Remove all files&quot;.</source>
<translation>Αυτός ο συγχρονισμός θα αφαιρέσει όλα τα αρχεία στον τοπικό φάκελο συγχρονισμού &apos;%1&apos;.
Εάν εσείς ή ο διαχειριστής σας επαναφέρατε τον λογαριασμό σας στο διακομιστή, επιλέξτε &quot;Διατήρηση αρχείων&quot;. Εάν θέλετε να αφαιρεθούν τα δεδομένα σας, επιλέξτε &quot;Αφαίρεση όλων των αρχείων&quot;.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="709"/>
<location filename="../src/mirall/folder.cpp" line="700"/>
<source>This sync would remove all the files in the sync folder '%1'.
This might be because the folder was silently reconfigured, or that all the file were manually removed.
Are you sure you want to perform this operation?</source>
@@ -362,17 +362,17 @@ Are you sure you want to perform this operation?</source>
Είστε σίγουροι ότι θέλετε να πραγματοποιήσετε αυτή εντολή;</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="713"/>
<location filename="../src/mirall/folder.cpp" line="704"/>
<source>Remove All Files?</source>
<translation>Αφαίρεση Όλων των Αρχείων;</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="715"/>
<location filename="../src/mirall/folder.cpp" line="706"/>
<source>Remove all files</source>
<translation>Αφαίρεση όλων των αρχείων</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="716"/>
<location filename="../src/mirall/folder.cpp" line="707"/>
<source>Keep files</source>
<translation>Διατήρηση αρχείων</translation>
</message>
@@ -596,17 +596,17 @@ Are you sure you want to perform this operation?</source>
<context>
<name>Mirall::GETFileJob</name>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="428"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="393"/>
<source>No E-Tag received from server, check Proxy/Gateway</source>
<translation>Δεν ελήφθη E-Tag από τον διακομιστή, ελέγξτε τον διακομιστή μεσολάβησης/πύλη</translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="435"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="400"/>
<source>We received a different E-Tag for resuming. Retrying next time.</source>
<translation>Ελήφθη διαφορετικό E-Tag για συνέχιση. Επανάληψη την επόμενη φορά.</translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="471"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="633"/>
<source>Connection Timeout</source>
<translation>Χρονικό όριο σύνδεσης</translation>
</message>
@@ -1278,7 +1278,7 @@ It is not advisable to use it.</source>
<context>
<name>Mirall::PropagateDownloadFileQNAM</name>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="485"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="443"/>
<source>File %1 can not be downloaded because of a local file name clash!</source>
<translation>Το αρχείο %1 δεν είναι δυνατό να μεταφορτωθεί λόγω διένεξης με το όνομα ενός τοπικού ονόματος αρχείου!</translation>
</message>
@@ -1336,17 +1336,17 @@ It is not advisable to use it.</source>
<context>
<name>Mirall::PropagateRemoteRename</name>
<message>
<location filename="../src/mirall/propagatorjobs.cpp" line="233"/>
<location filename="../src/mirall/propagatorjobs.cpp" line="242"/>
<source>This folder must not be renamed. It is renamed back to its original name.</source>
<translation>Αυτός ο φάκελος δεν πρέπει να μετονομαστεί. Μετονομάζεται πίσω στο αρχικό του όνομα.</translation>
</message>
<message>
<location filename="../src/mirall/propagatorjobs.cpp" line="235"/>
<location filename="../src/mirall/propagatorjobs.cpp" line="244"/>
<source>This folder must not be renamed. Please name it back to Shared.</source>
<translation>Αυτός ο φάκελος δεν πρέπει να μετονομαστεί. Παρακαλώ ονομάστε το ξανά Κοινόχρηστος.</translation>
</message>
<message>
<location filename="../src/mirall/propagatorjobs.cpp" line="250"/>
<location filename="../src/mirall/propagatorjobs.cpp" line="259"/>
<source>The file was renamed but is part of a read only share. The original file was restored.</source>
<translation>Το αρχείο μετονομάστηκε αλλά είναι τμήμα ενός διαμοιρασμένου καταλόγου μόνο για ανάγνωση. Το αρχικό αρχείο επαναφέρθηκε.</translation>
</message>
@@ -1378,12 +1378,12 @@ It is not advisable to use it.</source>
<translation>Το αρχείο υπέστη επεξεργασία τοπικά αλλά είναι τμήμα ενός διαμοιρασμένου καταλόγου μόνο για ανάγνωση. Επαναφέρθηκε και η επεξεργασία σας βρίσκεται στο αρχείο συγκρούσεων.</translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="278"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="272"/>
<source>Local file changed during sync.</source>
<translation>Το τοπικό αρχείο τροποποιήθηκε κατά τον συγχρονισμό.</translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="288"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="282"/>
<source>The server did not acknowledge the last chunk. (No e-tag were present)</source>
<translation>Ο διακομιστής δεν επιβεβαίωσε το τελευταίο τμήμα. (Δεν υπήρχε E-Tag)</translation>
</message>
@@ -1537,12 +1537,12 @@ It is not advisable to use it.</source>
<context>
<name>Mirall::ShibbolethCredentials</name>
<message>
<location filename="../src/creds/shibbolethcredentials.cpp" line="267"/>
<location filename="../src/creds/shibbolethcredentials.cpp" line="259"/>
<source>Login Error</source>
<translation>Σφάλμα σύνδεσης</translation>
</message>
<message>
<location filename="../src/creds/shibbolethcredentials.cpp" line="267"/>
<location filename="../src/creds/shibbolethcredentials.cpp" line="259"/>
<source>You must sign in as user %1</source>
<translation>Πρέπει να εισέλθετε σαν χρήστης %1</translation>
</message>
@@ -1925,27 +1925,27 @@ It is not advisable to use it.</source>
<translation>Το αντικείμενο δεν είναι συγχρονισμένο λόγω προηγούμενων σφαλμάτων: %1</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="280"/>
<location filename="../src/mirall/syncengine.cpp" line="274"/>
<source>Symbolic links are not supported in syncing.</source>
<translation>Οι συμβολικού σύνδεσμοι δεν υποστηρίζονται για το συγχρονισμό.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="283"/>
<location filename="../src/mirall/syncengine.cpp" line="277"/>
<source>File is listed on the ignore list.</source>
<translation>Το αρχείο περιέχεται στη λίστα αρχείων προς αγνόηση.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="286"/>
<location filename="../src/mirall/syncengine.cpp" line="280"/>
<source>File contains invalid characters that can not be synced cross platform.</source>
<translation>Το αρχείο περιέχει άκυρους χαρακτήρες που δεν μπορούν να συγχρονιστούν σε όλα τα συστήματα.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="453"/>
<location filename="../src/mirall/syncengine.cpp" line="448"/>
<source>Unable to initialize a sync journal.</source>
<translation>Αδυναμία προετοιμασίας αρχείου συγχρονισμού.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="549"/>
<location filename="../src/mirall/syncengine.cpp" line="545"/>
<source>Cannot open the sync journal</source>
<translation>Αποτυχία ανοίγματος του ημερολογίου συγχρονισμού.</translation>
</message>
+37 -37
Ver Arquivo
@@ -262,116 +262,116 @@
<context>
<name>Mirall::Folder</name>
<message>
<location filename="../src/mirall/folder.cpp" line="118"/>
<location filename="../src/mirall/folder.cpp" line="107"/>
<source>Unable to create csync-context</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="174"/>
<location filename="../src/mirall/folder.cpp" line="165"/>
<source>Local folder %1 does not exist.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="177"/>
<location filename="../src/mirall/folder.cpp" line="168"/>
<source>%1 should be a directory but is not.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="180"/>
<location filename="../src/mirall/folder.cpp" line="171"/>
<source>%1 is not readable.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="332"/>
<location filename="../src/mirall/folder.cpp" line="323"/>
<source>%1: %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="418"/>
<location filename="../src/mirall/folder.cpp" line="409"/>
<source>%1 and %2 other files have been removed.</source>
<comment>%1 names a file.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="420"/>
<location filename="../src/mirall/folder.cpp" line="411"/>
<source>%1 has been removed.</source>
<comment>%1 names a file.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="425"/>
<location filename="../src/mirall/folder.cpp" line="416"/>
<source>%1 and %2 other files have been downloaded.</source>
<comment>%1 names a file.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="427"/>
<location filename="../src/mirall/folder.cpp" line="418"/>
<source>%1 has been downloaded.</source>
<comment>%1 names a file.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="432"/>
<location filename="../src/mirall/folder.cpp" line="423"/>
<source>%1 and %2 other files have been updated.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="434"/>
<location filename="../src/mirall/folder.cpp" line="425"/>
<source>%1 has been updated.</source>
<comment>%1 names a file.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="439"/>
<location filename="../src/mirall/folder.cpp" line="430"/>
<source>%1 has been renamed to %2 and %3 other files have been renamed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="441"/>
<location filename="../src/mirall/folder.cpp" line="432"/>
<source>%1 has been renamed to %2.</source>
<comment>%1 and %2 name files.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="446"/>
<location filename="../src/mirall/folder.cpp" line="437"/>
<source>%1 has been moved to %2 and %3 other files have been moved.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="448"/>
<location filename="../src/mirall/folder.cpp" line="439"/>
<source>%1 has been moved to %2.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="456"/>
<location filename="../src/mirall/folder.cpp" line="447"/>
<source>Sync Activity</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="706"/>
<location filename="../src/mirall/folder.cpp" line="697"/>
<source>This sync would remove all the files in the local sync folder &apos;%1&apos;.
If you or your administrator have reset your account on the server, choose &quot;Keep files&quot;. If you want your data to be removed, choose &quot;Remove all files&quot;.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="709"/>
<location filename="../src/mirall/folder.cpp" line="700"/>
<source>This sync would remove all the files in the sync folder &apos;%1&apos;.
This might be because the folder was silently reconfigured, or that all the file were manually removed.
Are you sure you want to perform this operation?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="713"/>
<location filename="../src/mirall/folder.cpp" line="704"/>
<source>Remove All Files?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="715"/>
<location filename="../src/mirall/folder.cpp" line="706"/>
<source>Remove all files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="716"/>
<location filename="../src/mirall/folder.cpp" line="707"/>
<source>Keep files</source>
<translation type="unfinished"></translation>
</message>
@@ -595,17 +595,17 @@ Are you sure you want to perform this operation?</source>
<context>
<name>Mirall::GETFileJob</name>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="428"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="393"/>
<source>No E-Tag received from server, check Proxy/Gateway</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="435"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="400"/>
<source>We received a different E-Tag for resuming. Retrying next time.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="471"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="633"/>
<source>Connection Timeout</source>
<translation type="unfinished"></translation>
</message>
@@ -1273,7 +1273,7 @@ It is not advisable to use it.</source>
<context>
<name>Mirall::PropagateDownloadFileQNAM</name>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="485"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="443"/>
<source>File %1 can not be downloaded because of a local file name clash!</source>
<translation type="unfinished"></translation>
</message>
@@ -1331,17 +1331,17 @@ It is not advisable to use it.</source>
<context>
<name>Mirall::PropagateRemoteRename</name>
<message>
<location filename="../src/mirall/propagatorjobs.cpp" line="233"/>
<location filename="../src/mirall/propagatorjobs.cpp" line="242"/>
<source>This folder must not be renamed. It is renamed back to its original name.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/propagatorjobs.cpp" line="235"/>
<location filename="../src/mirall/propagatorjobs.cpp" line="244"/>
<source>This folder must not be renamed. Please name it back to Shared.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/propagatorjobs.cpp" line="250"/>
<location filename="../src/mirall/propagatorjobs.cpp" line="259"/>
<source>The file was renamed but is part of a read only share. The original file was restored.</source>
<translation type="unfinished"></translation>
</message>
@@ -1373,12 +1373,12 @@ It is not advisable to use it.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="278"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="272"/>
<source>Local file changed during sync.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="288"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="282"/>
<source>The server did not acknowledge the last chunk. (No e-tag were present)</source>
<translation type="unfinished"></translation>
</message>
@@ -1531,12 +1531,12 @@ It is not advisable to use it.</source>
<context>
<name>Mirall::ShibbolethCredentials</name>
<message>
<location filename="../src/creds/shibbolethcredentials.cpp" line="267"/>
<location filename="../src/creds/shibbolethcredentials.cpp" line="259"/>
<source>Login Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/creds/shibbolethcredentials.cpp" line="267"/>
<location filename="../src/creds/shibbolethcredentials.cpp" line="259"/>
<source>You must sign in as user %1</source>
<translation type="unfinished"></translation>
</message>
@@ -1917,27 +1917,27 @@ It is not advisable to use it.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="280"/>
<location filename="../src/mirall/syncengine.cpp" line="274"/>
<source>Symbolic links are not supported in syncing.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="283"/>
<location filename="../src/mirall/syncengine.cpp" line="277"/>
<source>File is listed on the ignore list.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="286"/>
<location filename="../src/mirall/syncengine.cpp" line="280"/>
<source>File contains invalid characters that can not be synced cross platform.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="453"/>
<location filename="../src/mirall/syncengine.cpp" line="448"/>
<source>Unable to initialize a sync journal.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="549"/>
<location filename="../src/mirall/syncengine.cpp" line="545"/>
<source>Cannot open the sync journal</source>
<translation type="unfinished"></translation>
</message>
+37 -37
Ver Arquivo
@@ -260,100 +260,100 @@
<context>
<name>Mirall::Folder</name>
<message>
<location filename="../src/mirall/folder.cpp" line="118"/>
<location filename="../src/mirall/folder.cpp" line="107"/>
<source>Unable to create csync-context</source>
<translation>Imposible crear csync-context</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="174"/>
<location filename="../src/mirall/folder.cpp" line="165"/>
<source>Local folder %1 does not exist.</source>
<translation>Carpeta local %1 no existe.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="177"/>
<location filename="../src/mirall/folder.cpp" line="168"/>
<source>%1 should be a directory but is not.</source>
<translation>%1 debería ser un directorio, pero no lo es.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="180"/>
<location filename="../src/mirall/folder.cpp" line="171"/>
<source>%1 is not readable.</source>
<translation>%1 es ilegible.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="332"/>
<location filename="../src/mirall/folder.cpp" line="323"/>
<source>%1: %2</source>
<translation>%1: %2</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="418"/>
<location filename="../src/mirall/folder.cpp" line="409"/>
<source>%1 and %2 other files have been removed.</source>
<comment>%1 names a file.</comment>
<translation>%1 y %2 otros archivos han sido eliminados.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="420"/>
<location filename="../src/mirall/folder.cpp" line="411"/>
<source>%1 has been removed.</source>
<comment>%1 names a file.</comment>
<translation>%1 ha sido eliminado.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="425"/>
<location filename="../src/mirall/folder.cpp" line="416"/>
<source>%1 and %2 other files have been downloaded.</source>
<comment>%1 names a file.</comment>
<translation>%1 y %2 otros archivos han sido descargados.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="427"/>
<location filename="../src/mirall/folder.cpp" line="418"/>
<source>%1 has been downloaded.</source>
<comment>%1 names a file.</comment>
<translation>%1 ha sido descargado.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="432"/>
<location filename="../src/mirall/folder.cpp" line="423"/>
<source>%1 and %2 other files have been updated.</source>
<translation>%1 y %2 otros archivos han sido actualizados.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="434"/>
<location filename="../src/mirall/folder.cpp" line="425"/>
<source>%1 has been updated.</source>
<comment>%1 names a file.</comment>
<translation>%1 ha sido actualizado.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="439"/>
<location filename="../src/mirall/folder.cpp" line="430"/>
<source>%1 has been renamed to %2 and %3 other files have been renamed.</source>
<translation>%1 ha sido renombrado a %2 y %3 otros archivos han sido renombrados.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="441"/>
<location filename="../src/mirall/folder.cpp" line="432"/>
<source>%1 has been renamed to %2.</source>
<comment>%1 and %2 name files.</comment>
<translation>%1 ha sido renombrado a %2.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="446"/>
<location filename="../src/mirall/folder.cpp" line="437"/>
<source>%1 has been moved to %2 and %3 other files have been moved.</source>
<translation>%1 ha sido movido a %2 y %3 otros archivos han sido movidos.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="448"/>
<location filename="../src/mirall/folder.cpp" line="439"/>
<source>%1 has been moved to %2.</source>
<translation>%1 ha sido movido a %2.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="456"/>
<location filename="../src/mirall/folder.cpp" line="447"/>
<source>Sync Activity</source>
<translation>Actividad en la Sincronización</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="706"/>
<location filename="../src/mirall/folder.cpp" line="697"/>
<source>This sync would remove all the files in the local sync folder '%1'.
If you or your administrator have reset your account on the server, choose &quot;Keep files&quot;. If you want your data to be removed, choose &quot;Remove all files&quot;.</source>
<translation>Esta sincronización eliminaría todos los archivos en la carpeta local de sincronización &apos;%1&apos;.
Si ud. o su administrador han restablecido su cuenta en el servidor, elija &quot;Conservar Archivos&quot;. Si desea eliminar toda su información, elija &quot;Eliminar todos los archivos&quot;.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="709"/>
<location filename="../src/mirall/folder.cpp" line="700"/>
<source>This sync would remove all the files in the sync folder '%1'.
This might be because the folder was silently reconfigured, or that all the file were manually removed.
Are you sure you want to perform this operation?</source>
@@ -362,17 +362,17 @@ Esto se puede deber a que la carpeta fue reconfigurada de forma silenciosa o a q
Está seguro de que desea realizar esta operación?</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="713"/>
<location filename="../src/mirall/folder.cpp" line="704"/>
<source>Remove All Files?</source>
<translation>Eliminar todos los archivos?</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="715"/>
<location filename="../src/mirall/folder.cpp" line="706"/>
<source>Remove all files</source>
<translation>Eliminar todos los archivos</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="716"/>
<location filename="../src/mirall/folder.cpp" line="707"/>
<source>Keep files</source>
<translation>Conservar archivos</translation>
</message>
@@ -596,17 +596,17 @@ Está seguro de que desea realizar esta operación?</translation>
<context>
<name>Mirall::GETFileJob</name>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="428"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="393"/>
<source>No E-Tag received from server, check Proxy/Gateway</source>
<translation>No se recibió ninguna e-tag del servidor, revisar el proxy/gateway</translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="435"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="400"/>
<source>We received a different E-Tag for resuming. Retrying next time.</source>
<translation>Se recibió una e-tag distinta para reanudar. Se intentará nuevamente.</translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="471"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="633"/>
<source>Connection Timeout</source>
<translation>Tiempo de espera de conexión agotado</translation>
</message>
@@ -1278,7 +1278,7 @@ No se recomienda usarlo.</translation>
<context>
<name>Mirall::PropagateDownloadFileQNAM</name>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="485"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="443"/>
<source>File %1 can not be downloaded because of a local file name clash!</source>
<translation>¡El fichero %1 no puede ser descargado debido al nombre de la clase de un fichero local!</translation>
</message>
@@ -1336,17 +1336,17 @@ No se recomienda usarlo.</translation>
<context>
<name>Mirall::PropagateRemoteRename</name>
<message>
<location filename="../src/mirall/propagatorjobs.cpp" line="233"/>
<location filename="../src/mirall/propagatorjobs.cpp" line="242"/>
<source>This folder must not be renamed. It is renamed back to its original name.</source>
<translation>Esta carpeta no debe ser renombrada. Ha sido renombrada a su nombre original</translation>
</message>
<message>
<location filename="../src/mirall/propagatorjobs.cpp" line="235"/>
<location filename="../src/mirall/propagatorjobs.cpp" line="244"/>
<source>This folder must not be renamed. Please name it back to Shared.</source>
<translation>Esta carpeta no debe ser renombrada. Favor de renombrar a Compartida.</translation>
</message>
<message>
<location filename="../src/mirall/propagatorjobs.cpp" line="250"/>
<location filename="../src/mirall/propagatorjobs.cpp" line="259"/>
<source>The file was renamed but is part of a read only share. The original file was restored.</source>
<translation>El archivo fue renombrado, pero es parte de una carpeta compartida en modo de solo lectura. El archivo original ha sido recuperado.</translation>
</message>
@@ -1378,12 +1378,12 @@ No se recomienda usarlo.</translation>
<translation>El archivo fue modificado localmente, pero es parte de una carpeta compartida en modo de solo lectura. Ha sido recuperado y tu modificación está en el archivo de conflicto.</translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="278"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="272"/>
<source>Local file changed during sync.</source>
<translation>Un archivo local fue modificado durante la sincronización.</translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="288"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="282"/>
<source>The server did not acknowledge the last chunk. (No e-tag were present)</source>
<translation>El servidor no reconoció la última parte. (No había una e-tag presente.)</translation>
</message>
@@ -1537,12 +1537,12 @@ Intente sincronizar los archivos nuevamente.</translation>
<context>
<name>Mirall::ShibbolethCredentials</name>
<message>
<location filename="../src/creds/shibbolethcredentials.cpp" line="267"/>
<location filename="../src/creds/shibbolethcredentials.cpp" line="259"/>
<source>Login Error</source>
<translation>Error al iniciar sesión</translation>
</message>
<message>
<location filename="../src/creds/shibbolethcredentials.cpp" line="267"/>
<location filename="../src/creds/shibbolethcredentials.cpp" line="259"/>
<source>You must sign in as user %1</source>
<translation>Debe iniciar sesión como el usuario %1</translation>
</message>
@@ -1925,27 +1925,27 @@ Intente sincronizar los archivos nuevamente.</translation>
<translation>El elemento no está sincronizado por errores previos: %1</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="280"/>
<location filename="../src/mirall/syncengine.cpp" line="274"/>
<source>Symbolic links are not supported in syncing.</source>
<translation>Los enlaces simbolicos no estan sopertados.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="283"/>
<location filename="../src/mirall/syncengine.cpp" line="277"/>
<source>File is listed on the ignore list.</source>
<translation>El fichero está en la lista de ignorados</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="286"/>
<location filename="../src/mirall/syncengine.cpp" line="280"/>
<source>File contains invalid characters that can not be synced cross platform.</source>
<translation>El fichero contiene caracteres inválidos que no pueden ser sincronizados con la plataforma.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="453"/>
<location filename="../src/mirall/syncengine.cpp" line="448"/>
<source>Unable to initialize a sync journal.</source>
<translation>No se pudo inicializar un registro (journal) de sincronización.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="549"/>
<location filename="../src/mirall/syncengine.cpp" line="545"/>
<source>Cannot open the sync journal</source>
<translation>No es posible abrir el diario de sincronización</translation>
</message>
+37 -37
Ver Arquivo
@@ -260,100 +260,100 @@
<context>
<name>Mirall::Folder</name>
<message>
<location filename="../src/mirall/folder.cpp" line="118"/>
<location filename="../src/mirall/folder.cpp" line="107"/>
<source>Unable to create csync-context</source>
<translation>Imposible crear csync-context</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="174"/>
<location filename="../src/mirall/folder.cpp" line="165"/>
<source>Local folder %1 does not exist.</source>
<translation>El directorio local %1 no existe.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="177"/>
<location filename="../src/mirall/folder.cpp" line="168"/>
<source>%1 should be a directory but is not.</source>
<translation>%1 debería ser un directorio, pero no lo es.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="180"/>
<location filename="../src/mirall/folder.cpp" line="171"/>
<source>%1 is not readable.</source>
<translation>No se puede leer %1.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="332"/>
<location filename="../src/mirall/folder.cpp" line="323"/>
<source>%1: %2</source>
<translation>%1: %2</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="418"/>
<location filename="../src/mirall/folder.cpp" line="409"/>
<source>%1 and %2 other files have been removed.</source>
<comment>%1 names a file.</comment>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="420"/>
<location filename="../src/mirall/folder.cpp" line="411"/>
<source>%1 has been removed.</source>
<comment>%1 names a file.</comment>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="425"/>
<location filename="../src/mirall/folder.cpp" line="416"/>
<source>%1 and %2 other files have been downloaded.</source>
<comment>%1 names a file.</comment>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="427"/>
<location filename="../src/mirall/folder.cpp" line="418"/>
<source>%1 has been downloaded.</source>
<comment>%1 names a file.</comment>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="432"/>
<location filename="../src/mirall/folder.cpp" line="423"/>
<source>%1 and %2 other files have been updated.</source>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="434"/>
<location filename="../src/mirall/folder.cpp" line="425"/>
<source>%1 has been updated.</source>
<comment>%1 names a file.</comment>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="439"/>
<location filename="../src/mirall/folder.cpp" line="430"/>
<source>%1 has been renamed to %2 and %3 other files have been renamed.</source>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="441"/>
<location filename="../src/mirall/folder.cpp" line="432"/>
<source>%1 has been renamed to %2.</source>
<comment>%1 and %2 name files.</comment>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="446"/>
<location filename="../src/mirall/folder.cpp" line="437"/>
<source>%1 has been moved to %2 and %3 other files have been moved.</source>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="448"/>
<location filename="../src/mirall/folder.cpp" line="439"/>
<source>%1 has been moved to %2.</source>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="456"/>
<location filename="../src/mirall/folder.cpp" line="447"/>
<source>Sync Activity</source>
<translation>Actividad de Sync</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="706"/>
<location filename="../src/mirall/folder.cpp" line="697"/>
<source>This sync would remove all the files in the local sync folder '%1'.
If you or your administrator have reset your account on the server, choose &quot;Keep files&quot;. If you want your data to be removed, choose &quot;Remove all files&quot;.</source>
<translation>Esta sincronización borraría todos los archivos en la carpeta local de sincronización &apos;%1&apos;.
Si vos o el administrador resetearon tu cuenta en el servidor, elegí &quot;Conservar Archivos&quot;. Si querés borrar toda tu información, elegí &quot;Borrar todos los archivos&quot;.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="709"/>
<location filename="../src/mirall/folder.cpp" line="700"/>
<source>This sync would remove all the files in the sync folder '%1'.
This might be because the folder was silently reconfigured, or that all the file were manually removed.
Are you sure you want to perform this operation?</source>
@@ -362,17 +362,17 @@ Esto se puede deber a que el directorio fue reconfigurado de manera silenciosa o
¿Estás seguro de que querés realizar esta operación?</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="713"/>
<location filename="../src/mirall/folder.cpp" line="704"/>
<source>Remove All Files?</source>
<translation>¿Borrar todos los archivos?</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="715"/>
<location filename="../src/mirall/folder.cpp" line="706"/>
<source>Remove all files</source>
<translation>Borrar todos los archivos</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="716"/>
<location filename="../src/mirall/folder.cpp" line="707"/>
<source>Keep files</source>
<translation>Conservar archivos</translation>
</message>
@@ -596,17 +596,17 @@ Esto se puede deber a que el directorio fue reconfigurado de manera silenciosa o
<context>
<name>Mirall::GETFileJob</name>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="428"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="393"/>
<source>No E-Tag received from server, check Proxy/Gateway</source>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="435"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="400"/>
<source>We received a different E-Tag for resuming. Retrying next time.</source>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="471"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="633"/>
<source>Connection Timeout</source>
<translation type="unfinished"/>
</message>
@@ -1276,7 +1276,7 @@ It is not advisable to use it.</source>
<context>
<name>Mirall::PropagateDownloadFileQNAM</name>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="485"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="443"/>
<source>File %1 can not be downloaded because of a local file name clash!</source>
<translation type="unfinished"/>
</message>
@@ -1334,17 +1334,17 @@ It is not advisable to use it.</source>
<context>
<name>Mirall::PropagateRemoteRename</name>
<message>
<location filename="../src/mirall/propagatorjobs.cpp" line="233"/>
<location filename="../src/mirall/propagatorjobs.cpp" line="242"/>
<source>This folder must not be renamed. It is renamed back to its original name.</source>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/propagatorjobs.cpp" line="235"/>
<location filename="../src/mirall/propagatorjobs.cpp" line="244"/>
<source>This folder must not be renamed. Please name it back to Shared.</source>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/propagatorjobs.cpp" line="250"/>
<location filename="../src/mirall/propagatorjobs.cpp" line="259"/>
<source>The file was renamed but is part of a read only share. The original file was restored.</source>
<translation type="unfinished"/>
</message>
@@ -1376,12 +1376,12 @@ It is not advisable to use it.</source>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="278"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="272"/>
<source>Local file changed during sync.</source>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="288"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="282"/>
<source>The server did not acknowledge the last chunk. (No e-tag were present)</source>
<translation type="unfinished"/>
</message>
@@ -1535,12 +1535,12 @@ Intente sincronizar estos nuevamente.</translation>
<context>
<name>Mirall::ShibbolethCredentials</name>
<message>
<location filename="../src/creds/shibbolethcredentials.cpp" line="267"/>
<location filename="../src/creds/shibbolethcredentials.cpp" line="259"/>
<source>Login Error</source>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/creds/shibbolethcredentials.cpp" line="267"/>
<location filename="../src/creds/shibbolethcredentials.cpp" line="259"/>
<source>You must sign in as user %1</source>
<translation type="unfinished"/>
</message>
@@ -1921,27 +1921,27 @@ Intente sincronizar estos nuevamente.</translation>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="280"/>
<location filename="../src/mirall/syncengine.cpp" line="274"/>
<source>Symbolic links are not supported in syncing.</source>
<translation>Los vínculos simbólicos no está soportados al sincronizar.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="283"/>
<location filename="../src/mirall/syncengine.cpp" line="277"/>
<source>File is listed on the ignore list.</source>
<translation>El archivo está en la lista de ignorados.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="286"/>
<location filename="../src/mirall/syncengine.cpp" line="280"/>
<source>File contains invalid characters that can not be synced cross platform.</source>
<translation>El archivo contiene caracteres inválidos que no pueden ser sincronizados entre plataforma.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="453"/>
<location filename="../src/mirall/syncengine.cpp" line="448"/>
<source>Unable to initialize a sync journal.</source>
<translation>Imposible inicializar un diario de sincronización.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="549"/>
<location filename="../src/mirall/syncengine.cpp" line="545"/>
<source>Cannot open the sync journal</source>
<translation type="unfinished"/>
</message>
+37 -37
Ver Arquivo
@@ -260,100 +260,100 @@
<context>
<name>Mirall::Folder</name>
<message>
<location filename="../src/mirall/folder.cpp" line="118"/>
<location filename="../src/mirall/folder.cpp" line="107"/>
<source>Unable to create csync-context</source>
<translation>Ei suuda luua csync-konteksti</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="174"/>
<location filename="../src/mirall/folder.cpp" line="165"/>
<source>Local folder %1 does not exist.</source>
<translation>Kohalikku kausta %1 pole olemas.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="177"/>
<location filename="../src/mirall/folder.cpp" line="168"/>
<source>%1 should be a directory but is not.</source>
<translation>%1 peaks olema kataloog, kuid pole seda mitte.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="180"/>
<location filename="../src/mirall/folder.cpp" line="171"/>
<source>%1 is not readable.</source>
<translation>%1 pole loetav.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="332"/>
<location filename="../src/mirall/folder.cpp" line="323"/>
<source>%1: %2</source>
<translation>%1: %2</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="418"/>
<location filename="../src/mirall/folder.cpp" line="409"/>
<source>%1 and %2 other files have been removed.</source>
<comment>%1 names a file.</comment>
<translation>%1 ja %2 teist faili eemaldati.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="420"/>
<location filename="../src/mirall/folder.cpp" line="411"/>
<source>%1 has been removed.</source>
<comment>%1 names a file.</comment>
<translation>%1 on eemaldatud.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="425"/>
<location filename="../src/mirall/folder.cpp" line="416"/>
<source>%1 and %2 other files have been downloaded.</source>
<comment>%1 names a file.</comment>
<translation>%1 ja %2 teist faili on alla laaditud.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="427"/>
<location filename="../src/mirall/folder.cpp" line="418"/>
<source>%1 has been downloaded.</source>
<comment>%1 names a file.</comment>
<translation>%1 on alla laaditud.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="432"/>
<location filename="../src/mirall/folder.cpp" line="423"/>
<source>%1 and %2 other files have been updated.</source>
<translation>%1 ja %2 teist faili on uuendatud.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="434"/>
<location filename="../src/mirall/folder.cpp" line="425"/>
<source>%1 has been updated.</source>
<comment>%1 names a file.</comment>
<translation>%1 on uuendatud.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="439"/>
<location filename="../src/mirall/folder.cpp" line="430"/>
<source>%1 has been renamed to %2 and %3 other files have been renamed.</source>
<translation>%1 on ümber nimetatud %2 ja %3 muud faili on samuti ümber nimetatud</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="441"/>
<location filename="../src/mirall/folder.cpp" line="432"/>
<source>%1 has been renamed to %2.</source>
<comment>%1 and %2 name files.</comment>
<translation>%1 on ümber nimetatud %2.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="446"/>
<location filename="../src/mirall/folder.cpp" line="437"/>
<source>%1 has been moved to %2 and %3 other files have been moved.</source>
<translation>%1 on tõstetud %2 ning %3 muud faili on samuti liigutatud.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="448"/>
<location filename="../src/mirall/folder.cpp" line="439"/>
<source>%1 has been moved to %2.</source>
<translation>%1 on tõstetud %2.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="456"/>
<location filename="../src/mirall/folder.cpp" line="447"/>
<source>Sync Activity</source>
<translation>Sünkroniseerimise tegevus</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="706"/>
<location filename="../src/mirall/folder.cpp" line="697"/>
<source>This sync would remove all the files in the local sync folder '%1'.
If you or your administrator have reset your account on the server, choose &quot;Keep files&quot;. If you want your data to be removed, choose &quot;Remove all files&quot;.</source>
<translation>See sünkroniseering kustutab kõik failid kohalikust kataloogist &apos;%1&apos;.
Kui sina või adminstraator on sinu konto serveris algseadistanud, siis vali &quot;Säilita failid&quot;. Kui soovid oma andmed kustutada, vali &quot;Kustuta kõik failid&quot;.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="709"/>
<location filename="../src/mirall/folder.cpp" line="700"/>
<source>This sync would remove all the files in the sync folder '%1'.
This might be because the folder was silently reconfigured, or that all the file were manually removed.
Are you sure you want to perform this operation?</source>
@@ -362,17 +362,17 @@ See võib olla põhjustatud kataloogi ümberseadistusest või on toimunud kõiki
Oled kindel, et soovid seda operatsiooni teostada?</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="713"/>
<location filename="../src/mirall/folder.cpp" line="704"/>
<source>Remove All Files?</source>
<translation>Kustutada kõik failid?</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="715"/>
<location filename="../src/mirall/folder.cpp" line="706"/>
<source>Remove all files</source>
<translation>Kustutada kõik failid</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="716"/>
<location filename="../src/mirall/folder.cpp" line="707"/>
<source>Keep files</source>
<translation>Säilita failid</translation>
</message>
@@ -596,17 +596,17 @@ Oled kindel, et soovid seda operatsiooni teostada?</translation>
<context>
<name>Mirall::GETFileJob</name>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="428"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="393"/>
<source>No E-Tag received from server, check Proxy/Gateway</source>
<translation>Ühtegi E-Silti ei saabunud serverist, kontrolli puhverserverit/lüüsi.</translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="435"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="400"/>
<source>We received a different E-Tag for resuming. Retrying next time.</source>
<translation>Saime jätkamiseks erineva E-Sildi. Proovin järgmine kord uuesti.</translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="471"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="633"/>
<source>Connection Timeout</source>
<translation>Ühenduse aegumine</translation>
</message>
@@ -1278,7 +1278,7 @@ Selle kasutamine pole soovitatav.</translation>
<context>
<name>Mirall::PropagateDownloadFileQNAM</name>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="485"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="443"/>
<source>File %1 can not be downloaded because of a local file name clash!</source>
<translation type="unfinished"/>
</message>
@@ -1336,17 +1336,17 @@ Selle kasutamine pole soovitatav.</translation>
<context>
<name>Mirall::PropagateRemoteRename</name>
<message>
<location filename="../src/mirall/propagatorjobs.cpp" line="233"/>
<location filename="../src/mirall/propagatorjobs.cpp" line="242"/>
<source>This folder must not be renamed. It is renamed back to its original name.</source>
<translation>Kausta ei tohi ümber nimetada. Kausta algne nimi taastati.</translation>
</message>
<message>
<location filename="../src/mirall/propagatorjobs.cpp" line="235"/>
<location filename="../src/mirall/propagatorjobs.cpp" line="244"/>
<source>This folder must not be renamed. Please name it back to Shared.</source>
<translation>Kausta nime ei tohi muuta. Palun pane selle nimeks tagasi Shared.</translation>
</message>
<message>
<location filename="../src/mirall/propagatorjobs.cpp" line="250"/>
<location filename="../src/mirall/propagatorjobs.cpp" line="259"/>
<source>The file was renamed but is part of a read only share. The original file was restored.</source>
<translation>Fail oli ümber nimetatud, kuid see on osa kirjutamisõiguseta jagamisest. Algne fail taastati.</translation>
</message>
@@ -1378,12 +1378,12 @@ Selle kasutamine pole soovitatav.</translation>
<translation>Faili on lokaalselt muudetud, kuid see on osa kirjutamisõiguseta jagamisest. See on taastatud ning sinu muudatus on konfliktses failis.</translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="278"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="272"/>
<source>Local file changed during sync.</source>
<translation>Kohalik fail muutus sünkroniseeringu käigus.</translation>
</message>
<message>
<location filename="../src/mirall/propagator_qnam.cpp" line="288"/>
<location filename="../src/mirall/propagator_qnam.cpp" line="282"/>
<source>The server did not acknowledge the last chunk. (No e-tag were present)</source>
<translation type="unfinished"/>
</message>
@@ -1537,12 +1537,12 @@ Proovi neid uuesti sünkroniseerida.</translation>
<context>
<name>Mirall::ShibbolethCredentials</name>
<message>
<location filename="../src/creds/shibbolethcredentials.cpp" line="267"/>
<location filename="../src/creds/shibbolethcredentials.cpp" line="259"/>
<source>Login Error</source>
<translation>Sisselogimise viga</translation>
</message>
<message>
<location filename="../src/creds/shibbolethcredentials.cpp" line="267"/>
<location filename="../src/creds/shibbolethcredentials.cpp" line="259"/>
<source>You must sign in as user %1</source>
<translation>Pead sisse logima kui kasutaja %1</translation>
</message>
@@ -1925,27 +1925,27 @@ Proovi neid uuesti sünkroniseerida.</translation>
<translation>Üksust ei sünkroniseeritud eelnenud vigade tõttu: %1</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="280"/>
<location filename="../src/mirall/syncengine.cpp" line="274"/>
<source>Symbolic links are not supported in syncing.</source>
<translation>Sümboolsed lingid ei ole sünkroniseerimisel toetatud.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="283"/>
<location filename="../src/mirall/syncengine.cpp" line="277"/>
<source>File is listed on the ignore list.</source>
<translation>Fail on märgitud ignoreeritavate nimistus.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="286"/>
<location filename="../src/mirall/syncengine.cpp" line="280"/>
<source>File contains invalid characters that can not be synced cross platform.</source>
<translation>Fail sisaldab sobimatuid sümboleid, mida ei saa sünkroniseerida erinevate platvormide vahel.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="453"/>
<location filename="../src/mirall/syncengine.cpp" line="448"/>
<source>Unable to initialize a sync journal.</source>
<translation>Ei suuda lähtestada sünkroniseeringu zurnaali.</translation>
</message>
<message>
<location filename="../src/mirall/syncengine.cpp" line="549"/>
<location filename="../src/mirall/syncengine.cpp" line="545"/>
<source>Cannot open the sync journal</source>
<translation>Ei suuda avada sünkroniseeringu zurnaali</translation>
</message>

Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais