Comparar commits

..

1 Commits

Autor SHA1 Mensagem Data
Klaas Freitag 0f37484b8a Bumped the release number to 1.6.2, Changelog additions. 2014-07-28 11:44:10 +02:00
118 arquivos alterados com 4238 adições e 4148 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 {
+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.
+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>
+37 -37
Ver Arquivo
@@ -260,116 +260,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"/>
</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>Bertako %1 karpeta ez da existitzen.</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 karpeta bat izan behar zen baina ez da.</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 ezin da irakurri.</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>%1 ezabatua izan da.</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"/>
</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>%1 %2-(e)ra mugitu da.</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="456"/>
<location filename="../src/mirall/folder.cpp" line="447"/>
<source>Sync Activity</source>
<translation>Sinkronizazio Jarduerak</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 type="unfinished"/>
</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>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="713"/>
<location filename="../src/mirall/folder.cpp" line="704"/>
<source>Remove All Files?</source>
<translation>Ezabatu Fitxategi Guztiak?</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>Ezabatu fitxategi guztiak</translation>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="716"/>
<location filename="../src/mirall/folder.cpp" line="707"/>
<source>Keep files</source>
<translation>Mantendu fitxategiak</translation>
</message>
@@ -593,17 +593,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>Ez da E-Tagik jaso zerbitzaritik, egiaztatu 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 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>
@@ -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"/>
</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>Karpeta hau ezin da berrizendatu. Bere jatorrizko izenera berrizendatu da.</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>Karpeta hau ezin da berrizendatu. Mesedez jarri berriz Shared izena.</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>
@@ -1373,12 +1373,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>
@@ -1532,12 +1532,12 @@ Saiatu horiek berriz sinkronizatzen.</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>
@@ -1918,27 +1918,27 @@ Saiatu horiek berriz sinkronizatzen.</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>Esteka sinbolikoak ezin dira sinkronizatu.</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>Fitxategia baztertutakoen zerrendan dago.</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"/>
</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>Ezin izan da sinkronizazio egunerokoa hasieratu.</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,116 +260,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"/>
</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 type="unfinished"/>
</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 type="unfinished"/>
</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 type="unfinished"/>
</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>
<translation type="unfinished"/>
</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"/>
</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"/>
</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"/>
</message>
@@ -593,17 +593,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"/>
</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>
@@ -1271,7 +1271,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>
@@ -1329,17 +1329,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>
@@ -1371,12 +1371,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>
@@ -1529,12 +1529,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"/>
</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>
@@ -1915,27 +1915,27 @@ It is not advisable to use it.</source>
<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 type="unfinished"/>
</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"/>
</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"/>
</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"/>
</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,116 +260,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"/>
</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>Paikallista kansiota %1 ei ole olemassa.</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>Kohteen %1 pitäisi olla kansio, mutta se ei kuitenkaan ole kansio.</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 ei ole luettavissa.</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>%1 on poistettu.</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"/>
</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 ladattu.</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"/>
</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 päivitetty.</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>%1 on nimetty uudeelleen muotoon %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 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>%1 on siirretty kohteeseen %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>Synkronointiaktiviteetti</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 type="unfinished"/>
</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>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/mirall/folder.cpp" line="713"/>
<location filename="../src/mirall/folder.cpp" line="704"/>
<source>Remove All Files?</source>
<translation>Poistetaanko kaikki tiedostot?</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>Poista kaikki tiedostot</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äilytä tiedostot</translation>
</message>
@@ -593,17 +593,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"/>
</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>Yhteys aikakatkaistiin</translation>
</message>
@@ -1273,7 +1273,7 @@ Osoitteen käyttäminen ei ole suositeltavaa.</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>
@@ -1331,17 +1331,17 @@ Osoitteen käyttäminen ei ole suositeltavaa.</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>Tätä kansiota ei ole tule nimetä uudelleen. Muutetaan takaisin alkuperäinen nimi.</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"/>
</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>
@@ -1373,12 +1373,12 @@ Osoitteen käyttäminen ei ole suositeltavaa.</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>Paikallinen tiedosto muuttui synkronoinnin aikana.</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>
@@ -1531,12 +1531,12 @@ Osoitteen käyttäminen ei ole suositeltavaa.</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>Kirjautumisvirhe</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>Kirjaudu käyttäjänä %1</translation>
</message>
@@ -1919,27 +1919,27 @@ Osoitteen käyttäminen ei ole suositeltavaa.</translation>
<translation>Kohdetta ei synkronoitu aiempien virheiden vuoksi: %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>Symboliset linkit eivät ole tuettuja synkronoinnissa.</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"/>
</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"/>
</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"/>
</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>

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