mirror of
https://github.com/nextcloud/desktop.git
synced 2025-10-26 11:17:43 +00:00
Merge branch 'timedelta' into dav
This commit is contained in:
commit
cad3da10db
@ -46,6 +46,10 @@ endif()
|
||||
|
||||
include(ConfigureChecks.cmake)
|
||||
configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
||||
|
||||
set(SOURCE_DIR ${CMAKE_SOURCE_DIR})
|
||||
configure_file(config_test.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config_test.h)
|
||||
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
macro_copy_file(${CMAKE_CURRENT_SOURCE_DIR}/CTestCustom.cmake ${CMAKE_CURRENT_BINARY_DIR}/CTestCustom.cmake)
|
||||
@ -61,8 +65,10 @@ add_subdirectory(config)
|
||||
add_subdirectory(doc)
|
||||
|
||||
find_package(Check)
|
||||
if (CHECK_FOUND AND UNIT_TESTING)
|
||||
if (CHECK_FOUND)
|
||||
include(MacroAddCheckTest)
|
||||
endif (CHECK_FOUND)
|
||||
if (UNIT_TESTING)
|
||||
add_subdirectory(tests)
|
||||
endif (CHECK_FOUND AND UNIT_TESTING)
|
||||
endif(UNIT_TESTING)
|
||||
|
||||
|
||||
41
cmake/Modules/FindCMocka.cmake
Normal file
41
cmake/Modules/FindCMocka.cmake
Normal file
@ -0,0 +1,41 @@
|
||||
# - Try to find CMocka, the testing framework
|
||||
# Once done this will define
|
||||
#
|
||||
# CMOCKA_FOUND - system has CMocka
|
||||
# CMOCKA_INCLUDE_DIRS - the CMocka include directory
|
||||
# CMOCKA_LIBRARIES - Link these to use CMocka
|
||||
# CMOCKA_DEFINITIONS - Compiler switches required for using CMocka
|
||||
#
|
||||
# Copyright (c) 2007 Andreas Schneider <mail@cynapses.org>
|
||||
# (c) 2012 Dominik Schmidt <dev@dominik-schmidt.org>
|
||||
# (c) 2012 Klaas Freitag <freitag@owncloud.com>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the New
|
||||
# BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
#
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
find_path(CMOCKA_INCLUDE_DIRS
|
||||
NAMES
|
||||
cmocka.h
|
||||
HINTS
|
||||
${CMAKE_INSTALL_INCLUDEDIR}
|
||||
)
|
||||
|
||||
find_library(CMOCKA_LIBRARIES
|
||||
NAMES
|
||||
cmocka
|
||||
HINTS
|
||||
${CMAKE_INSTALL_PREFIX}/lib
|
||||
${CMAKE_INSTALL_PREFIX}/lib64
|
||||
${CMAKE_INSTALL_LIBDIR}
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Cmocka
|
||||
REQUIRED_VARS CMOCKA_LIBRARIES CMOCKA_INCLUDE_DIRS
|
||||
)
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
* along with this program = NULL, if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
@ -40,6 +40,7 @@
|
||||
|
||||
#include "c_lib.h"
|
||||
#include "csync.h"
|
||||
#include "csync_misc.h"
|
||||
#include "c_private.h"
|
||||
|
||||
#include "vio/csync_vio_module.h"
|
||||
@ -54,6 +55,10 @@
|
||||
#define DEBUG_WEBDAV(...) CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define OC_TIMEDELTA_FAIL (NE_REDIRECT +1)
|
||||
#define OC_PROPFIND_FAIL (NE_REDIRECT +2)
|
||||
|
||||
|
||||
enum resource_type {
|
||||
resr_normal = 0,
|
||||
resr_collection,
|
||||
@ -119,6 +124,11 @@ struct dav_session_s {
|
||||
ne_session *ctx;
|
||||
char *user;
|
||||
char *pwd;
|
||||
|
||||
time_t prev_delta;
|
||||
time_t time_delta; /* The time delta to use. */
|
||||
long int time_delta_sum; /* What is the time delta average? */
|
||||
int time_delta_cnt; /* How often was the server time gathered? */
|
||||
};
|
||||
|
||||
/* The list of properties that is fetched in PropFind on a collection */
|
||||
@ -347,6 +357,10 @@ static int dav_connect(const char *base_url) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
dav_session.time_delta_sum = 0;
|
||||
dav_session.time_delta_cnt = 0;
|
||||
dav_session.prev_delta = 0;
|
||||
|
||||
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 );
|
||||
@ -505,14 +519,59 @@ static int fetch_resource_list( const char *curi,
|
||||
struct listdir_context *fetchCtx )
|
||||
{
|
||||
int ret = 0;
|
||||
ne_propfind_handler *hdl = NULL;
|
||||
ne_request *request = NULL;
|
||||
const char *date_header = NULL;
|
||||
time_t server_time;
|
||||
time_t now;
|
||||
time_t time_diff;
|
||||
time_t time_diff_delta;
|
||||
|
||||
/* do a propfind request and parse the results in the results function, set as callback */
|
||||
ret = ne_simple_propfind( dav_session.ctx, curi, depth, ls_props, results, fetchCtx );
|
||||
/* ret = ne_simple_propfind( dav_session.ctx, curi, depth, ls_props, results, fetchCtx ); */
|
||||
|
||||
hdl = ne_propfind_create(dav_session.ctx, curi, depth);
|
||||
|
||||
ret = ne_propfind_named(hdl, ls_props, results, fetchCtx);
|
||||
|
||||
if( ret == NE_OK ) {
|
||||
DEBUG_WEBDAV("Simple propfind OK.");
|
||||
fetchCtx->currResource = fetchCtx->list;
|
||||
request = ne_propfind_get_request( hdl );
|
||||
|
||||
date_header = ne_get_response_header( request, "Date" );
|
||||
DEBUG_WEBDAV("Server Date from HTTP header value: %s", date_header);
|
||||
server_time = ne_rfc1123_parse( date_header );
|
||||
now = time(NULL);
|
||||
time_diff = server_time - now;
|
||||
|
||||
dav_session.time_delta_sum += time_diff;
|
||||
dav_session.time_delta_cnt++;
|
||||
|
||||
/* Store the previous time delta */
|
||||
dav_session.prev_delta = dav_session.time_delta;
|
||||
|
||||
/* check the changing of the time delta */
|
||||
time_diff_delta = llabs(dav_session.time_delta - time_diff);
|
||||
if( dav_session.time_delta_cnt == 1 ) {
|
||||
DEBUG_WEBDAV( "The first time_delta is %d", time_diff );
|
||||
} else if( dav_session.time_delta_cnt > 1 ) {
|
||||
if( time_diff_delta > 5 ) {
|
||||
DEBUG_WEBDAV("WRN: The time delta changed more than 5 second");
|
||||
ret = OC_TIMEDELTA_FAIL;
|
||||
} else {
|
||||
DEBUG_WEBDAV("Ok: Time delta remained (almost) the same: %ld.", time_diff);
|
||||
}
|
||||
} else {
|
||||
DEBUG_WEBDAV("Difference to last server time delta: %d", time_diff_delta );
|
||||
}
|
||||
dav_session.time_delta = time_diff;
|
||||
} else {
|
||||
DEBUG_WEBDAV("WRN: propfind named failed with %d", ret);
|
||||
}
|
||||
|
||||
ne_propfind_destroy(hdl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -545,6 +604,7 @@ static csync_vio_file_stat_t *resourceToFileStat( struct resource *res )
|
||||
DEBUG_WEBDAV("ERROR: Unknown resource type %d", res->type);
|
||||
}
|
||||
|
||||
/* Correct the mtime of the file with the server time delta */
|
||||
lfs->mtime = res->modtime;
|
||||
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME;
|
||||
lfs->size = res->size;
|
||||
@ -654,6 +714,7 @@ static int owncloud_stat(const char *uri, csync_vio_file_stat_t *buf) {
|
||||
buf->fields = _fs.fields;
|
||||
buf->type = _fs.type;
|
||||
buf->mtime = _fs.mtime;
|
||||
|
||||
buf->size = _fs.size;
|
||||
buf->mode = _stat_perms( _fs.type );
|
||||
} else {
|
||||
@ -675,9 +736,14 @@ static int owncloud_stat(const char *uri, csync_vio_file_stat_t *buf) {
|
||||
|
||||
rc = fetch_resource_list( curi, NE_DEPTH_ONE, fetchCtx );
|
||||
if( rc != NE_OK ) {
|
||||
errno = ne_session_error_errno( dav_session.ctx );
|
||||
if( rc == OC_TIMEDELTA_FAIL ) {
|
||||
DEBUG_WEBDAV("WRN: Time delta changed too much!");
|
||||
/* FIXME: Reasonable user warning */
|
||||
} else {
|
||||
errno = ne_session_error_errno( dav_session.ctx );
|
||||
|
||||
DEBUG_WEBDAV("stat fails with errno %d", errno );
|
||||
DEBUG_WEBDAV("stat fails with errno %d", errno );
|
||||
}
|
||||
free_fetchCtx(fetchCtx);
|
||||
return -1;
|
||||
}
|
||||
@ -846,6 +912,22 @@ static void install_content_reader( ne_request *req, void *userdata, const ne_st
|
||||
|
||||
static char*_lastDir = NULL;
|
||||
|
||||
/* capabilities are currently:
|
||||
* bool atomar_copy_support - oC provides atomar copy
|
||||
* bool do_post_copy_stat - oC does not want the post copy check
|
||||
* bool time_sync_required - oC does not require the time sync
|
||||
* int unix_extensions - oC supports unix extensions.
|
||||
*/
|
||||
static csync_vio_capabilities_t _owncloud_capabilities = { true, false, false, 1 };
|
||||
|
||||
static csync_vio_capabilities_t *owncloud_get_capabilities(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
_owncloud_capabilities.unix_extensions = 0;
|
||||
#endif
|
||||
return &_owncloud_capabilities;
|
||||
}
|
||||
|
||||
static csync_vio_method_handle_t *owncloud_open(const char *durl,
|
||||
int flags,
|
||||
mode_t mode) {
|
||||
@ -1132,7 +1214,6 @@ static int owncloud_close(csync_vio_method_handle_t *fhandle) {
|
||||
errno = EBADF;
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (rc == NE_OK) {
|
||||
if ( ne_get_status( writeCtx->req )->klass != 2 ) {
|
||||
DEBUG_WEBDAV("Error - PUT status value no 2xx");
|
||||
@ -1459,6 +1540,8 @@ static int owncloud_utimes(const char *uri, const struct timeval *times) {
|
||||
int rc = NE_OK;
|
||||
char val[255];
|
||||
char *curi = NULL;
|
||||
const struct timeval *modtime = times+1;
|
||||
long newmodtime;
|
||||
|
||||
curi = _cleanPath( uri );
|
||||
|
||||
@ -1473,7 +1556,13 @@ static int owncloud_utimes(const char *uri, const struct timeval *times) {
|
||||
pname.nspace = NULL;
|
||||
pname.name = "lastmodified";
|
||||
|
||||
snprintf( val, sizeof(val), "%ld", times->tv_sec );
|
||||
newmodtime = modtime->tv_sec;
|
||||
#if TIMEDELTA
|
||||
DEBUG_WEBDAV("Add a time delta to modtime %lu: %ld",
|
||||
modtime->tv_sec, dav_session.time_delta);
|
||||
newmodtime += dav_session.time_delta;
|
||||
#endif
|
||||
snprintf( val, sizeof(val), "%ld", newmodtime );
|
||||
DEBUG_WEBDAV("Setting LastModified of %s to %s", curi, val );
|
||||
|
||||
ops[0].name = &pname;
|
||||
@ -1495,6 +1584,7 @@ static int owncloud_utimes(const char *uri, const struct timeval *times) {
|
||||
|
||||
csync_vio_method_t _method = {
|
||||
.method_table_size = sizeof(csync_vio_method_t),
|
||||
.get_capabilities = owncloud_get_capabilities,
|
||||
.open = owncloud_open,
|
||||
.creat = owncloud_creat,
|
||||
.close = owncloud_close,
|
||||
@ -1518,12 +1608,11 @@ csync_vio_method_t *vio_module_init(const char *method_name, const char *args,
|
||||
csync_auth_callback cb, void *userdata) {
|
||||
(void) method_name;
|
||||
(void) args;
|
||||
|
||||
_authcb = cb;
|
||||
_userdata = userdata;
|
||||
_connected = 0; /* triggers dav_connect to go through the whole neon setup */
|
||||
|
||||
/* DEBUG_WEBDAV("********** vio_module_init "); */
|
||||
|
||||
return &_method;
|
||||
}
|
||||
|
||||
@ -1539,6 +1628,4 @@ void vio_module_shutdown(csync_vio_method_t *method) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* vim: set ts=4 sw=4 et cindent: */
|
||||
|
||||
@ -4,6 +4,7 @@ add_subdirectory(std)
|
||||
|
||||
find_package(SQLite3 REQUIRED)
|
||||
find_package(Iniparser REQUIRED)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
|
||||
set(CSYNC_PUBLIC_INCLUDE_DIRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
@ -12,6 +13,7 @@ set(CSYNC_PUBLIC_INCLUDE_DIRS
|
||||
)
|
||||
|
||||
set(CSYNC_PRIVATE_INCLUDE_DIRS
|
||||
${OPENSSL_INCLUDE_DIRS}
|
||||
${INIPARSER_INCLUDE_DIRS}
|
||||
${SQLITE3_INCLUDE_DIRS}
|
||||
${CSTDLIB_PUBLIC_INCLUDE_DIRS}
|
||||
@ -28,7 +30,7 @@ set(CSYNC_LINK_LIBRARIES
|
||||
${CSTDLIB_LIBRARY}
|
||||
${CSYNC_REQUIRED_LIBRARIES}
|
||||
${INIPARSER_LIBRARIES}
|
||||
|
||||
${OPENSSL_LIBRARIES}
|
||||
${SQLITE3_LIBRARIES}
|
||||
)
|
||||
|
||||
|
||||
69
src/csync.c
69
src/csync.c
@ -121,7 +121,6 @@ int csync_create(CSYNC **csync, const char *local, const char *remote) {
|
||||
ctx->options.unix_extensions = 0;
|
||||
ctx->options.with_conflict_copys=false;
|
||||
ctx->options.local_only_mode = false;
|
||||
ctx->options.remote_push_atomar = false;
|
||||
|
||||
ctx->pwd.uid = getuid();
|
||||
ctx->pwd.euid = geteuid();
|
||||
@ -315,29 +314,38 @@ retry_vio_init:
|
||||
ctx->remote.type = LOCAL_REPLICA;
|
||||
}
|
||||
|
||||
if( !ctx->options.local_only_mode ) {
|
||||
if(!ctx->options.local_only_mode) {
|
||||
if(ctx->module.capabilities.time_sync_required) {
|
||||
timediff = csync_timediff(ctx);
|
||||
if (timediff > ctx->options.max_time_difference) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL,
|
||||
"Clock skew detected. The time difference is greater than %d seconds!",
|
||||
ctx->options.max_time_difference);
|
||||
ctx->error_code = CSYNC_ERR_TIMESKEW;
|
||||
rc = -1;
|
||||
goto out;
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL,
|
||||
"Clock skew detected. The time difference is greater than %d seconds!",
|
||||
ctx->options.max_time_difference);
|
||||
ctx->error_code = CSYNC_ERR_TIMESKEW;
|
||||
rc = -1;
|
||||
goto out;
|
||||
} else if (timediff < 0) {
|
||||
/* error code was set in csync_timediff() */
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL, "Synchronisation is not possible!");
|
||||
ctx->error_code = CSYNC_ERR_TIMESKEW;
|
||||
rc = -1;
|
||||
goto out;
|
||||
/* error code was set in csync_timediff() */
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL, "Synchronisation is not possible!");
|
||||
ctx->error_code = CSYNC_ERR_TIMESKEW;
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Module does not need time synchronization.");
|
||||
}
|
||||
|
||||
if(ctx->module.capabilities.unix_extensions == -1) { /* detect */
|
||||
if (csync_unix_extensions(ctx) < 0) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL, "Could not detect filesystem type.");
|
||||
ctx->error_code = CSYNC_ERR_FILESYSTEM;
|
||||
rc = -1;
|
||||
goto out;
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL, "Could not detect filesystem type.");
|
||||
ctx->error_code = CSYNC_ERR_FILESYSTEM;
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/* The module specifies the value for the unix_extensions. */
|
||||
ctx->options.unix_extensions = ctx->module.capabilities.unix_extensions;
|
||||
}
|
||||
}
|
||||
|
||||
if (c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp) < 0) {
|
||||
@ -938,33 +946,6 @@ bool csync_get_local_only(CSYNC *ctx) {
|
||||
return ctx->options.local_only_mode;
|
||||
}
|
||||
|
||||
int csync_set_remote_push_atomar(CSYNC *ctx, bool is_atomar) {
|
||||
if(ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->error_code = CSYNC_ERR_NONE;
|
||||
|
||||
if (ctx->status & CSYNC_STATUS_PROPAGATE) {
|
||||
fprintf(stderr, "This function must be called before propagation.");
|
||||
ctx->error_code = CSYNC_ERR_UNSPEC;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->options.remote_push_atomar = is_atomar;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool csync_get_remote_push_atomar(CSYNC *ctx) {
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
ctx->error_code = CSYNC_ERR_NONE;
|
||||
|
||||
return ctx->options.remote_push_atomar;
|
||||
}
|
||||
|
||||
CSYNC_ERROR_CODE csync_get_error(CSYNC *ctx) {
|
||||
if (ctx == NULL) {
|
||||
return CSYNC_ERR_PARAM;
|
||||
|
||||
17
src/csync.h
17
src/csync.h
@ -375,23 +375,6 @@ int csync_set_local_only( CSYNC *ctx, bool local_only );
|
||||
*/
|
||||
bool csync_get_local_only( CSYNC *ctx );
|
||||
|
||||
/**
|
||||
* @brief Flag to tell csync that the push to remote is atomar and no temp file is needed.
|
||||
*
|
||||
* @param local_only Bool flag to indicate atomar remote push
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occured.
|
||||
*/
|
||||
int csync_set_remote_push_atomar(CSYNC *ctx, bool is_atomar);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the flag if the remote push is atomar and needs no temp file in between.
|
||||
*
|
||||
* @return 1: remote push is atomar, 0: use temp file to push
|
||||
*/
|
||||
bool csync_get_remote_push_atomar( CSYNC *ctx );
|
||||
|
||||
|
||||
/* Used for special modes or debugging */
|
||||
int csync_get_status(CSYNC *ctx);
|
||||
|
||||
|
||||
@ -108,6 +108,7 @@ struct csync_s {
|
||||
void *handle;
|
||||
csync_vio_method_t *method;
|
||||
csync_vio_method_finish_fn finish_fn;
|
||||
csync_vio_capabilities_t capabilities;
|
||||
} module;
|
||||
|
||||
struct {
|
||||
|
||||
@ -51,7 +51,7 @@ static bool _push_to_tmp_first(CSYNC *ctx)
|
||||
if( ctx->current == REMOTE_REPLCIA ) return true; /* Always push to tmp for destination local file system */
|
||||
|
||||
/* If destination is the remote replica check if the switch is set. */
|
||||
if( !ctx->options.remote_push_atomar ) return true; /* DO push to tmp first */
|
||||
if( !ctx->module.capabilities.atomar_copy_support ) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -286,46 +286,50 @@ static int _csync_push_file(CSYNC *ctx, csync_file_stat_t *st) {
|
||||
}
|
||||
dfp = NULL;
|
||||
|
||||
/*
|
||||
* Check filesize
|
||||
*/
|
||||
ctx->replica = drep;
|
||||
tstat = csync_vio_file_stat_new();
|
||||
if (tstat == NULL) {
|
||||
strerror_r(errno, errbuf, sizeof(errbuf));
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
||||
"file: %s, command: stat, error: %s",
|
||||
turi,
|
||||
errbuf);
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
#if 0
|
||||
if (csync_vio_stat(ctx, turi, tstat) < 0) {
|
||||
switch (errno) {
|
||||
if( ctx->module.capabilities.do_post_copy_stat ) {
|
||||
/*
|
||||
* Check filesize
|
||||
* In case the transport is secure and/or the stat is expensive, this check
|
||||
* could be skipped through module capabilities definitions.
|
||||
*/
|
||||
|
||||
ctx->replica = drep;
|
||||
tstat = csync_vio_file_stat_new();
|
||||
if (tstat == NULL) {
|
||||
strerror_r(errno, errbuf, sizeof(errbuf));
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
||||
"file: %s, command: stat, error: %s",
|
||||
turi,
|
||||
errbuf);
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (csync_vio_stat(ctx, turi, tstat) < 0) {
|
||||
switch (errno) {
|
||||
case ENOMEM:
|
||||
rc = -1;
|
||||
break;
|
||||
default:
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
strerror_r(errno, errbuf, sizeof(errbuf));
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
||||
"file: %s, command: stat, error: %s",
|
||||
turi,
|
||||
errbuf);
|
||||
goto out;
|
||||
}
|
||||
strerror_r(errno, errbuf, sizeof(errbuf));
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
||||
"file: %s, command: stat, error: %s",
|
||||
turi,
|
||||
errbuf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (st->size != tstat->size) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
||||
"file: %s, error: incorrect filesize (size: %jd should be %jd)",
|
||||
turi, tstat->size, st->size);
|
||||
rc = 1;
|
||||
goto out;
|
||||
if (st->size != tstat->size) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
||||
"file: %s, error: incorrect filesize (size: %jd should be %jd)",
|
||||
turi, tstat->size, st->size);
|
||||
rc = 1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (_push_to_tmp_first(ctx)) {
|
||||
/* override original file */
|
||||
|
||||
@ -101,6 +101,8 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
||||
tmp = csync_statedb_get_stat_by_hash(ctx, h);
|
||||
if (tmp && tmp->phash == h) {
|
||||
/* we have an update! */
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "time compare: %lu <-> %lu",
|
||||
fs->mtime, tmp->modtime);
|
||||
if (fs->mtime > tmp->modtime) {
|
||||
st->instruction = CSYNC_INSTRUCTION_EVAL;
|
||||
goto out;
|
||||
|
||||
@ -32,6 +32,14 @@
|
||||
#include "csync_util.h"
|
||||
#include "vio/csync_vio.h"
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# define COMMON_DIGEST_FOR_OPENSSL
|
||||
# include <CommonCrypto/CommonDigest.h>
|
||||
# define SHA1 CC_SHA1
|
||||
#else
|
||||
# include <openssl/md5.h>
|
||||
#endif
|
||||
|
||||
#define CSYNC_LOG_CATEGORY_NAME "csync.util"
|
||||
#include "csync_log.h"
|
||||
|
||||
@ -326,4 +334,68 @@ uint64_t csync_create_statedb_hash(CSYNC *ctx) {
|
||||
return hash;
|
||||
}
|
||||
|
||||
static char* digest_to_out(unsigned char* digest)
|
||||
{
|
||||
char *out = c_malloc(33);
|
||||
int n;
|
||||
|
||||
if( !digest ) return NULL;
|
||||
|
||||
for (n = 0; n < 16; ++n) {
|
||||
snprintf(&(out[n*2]), 16*2, "%02x", (unsigned int) *(digest+n));
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
#define BUF_SIZE 512
|
||||
|
||||
char* csync_file_md5(const char *filename)
|
||||
{
|
||||
const char *tmpFileName;
|
||||
int fd;
|
||||
MD5_CTX c;
|
||||
char buf[ BUF_SIZE+1 ];
|
||||
unsigned char digest[16];
|
||||
size_t size;
|
||||
|
||||
tmpFileName = c_multibyte( filename );
|
||||
|
||||
if ( (fd = _topen( tmpFileName, O_RDONLY )) < 0) {
|
||||
return NULL;
|
||||
} else {
|
||||
MD5_Init(&c);
|
||||
while( (size=read(fd, buf, BUF_SIZE )) > 0) {
|
||||
buf[size]='\0';
|
||||
MD5_Update(&c, buf, size);
|
||||
}
|
||||
close(fd);
|
||||
MD5_Final(digest, &c);
|
||||
}
|
||||
|
||||
c_free_multibyte(tmpFileName);
|
||||
return digest_to_out(digest);
|
||||
}
|
||||
|
||||
char* csync_buffer_md5(const char *str, int length)
|
||||
{
|
||||
MD5_CTX c;
|
||||
unsigned char digest[16];
|
||||
|
||||
MD5_Init(&c);
|
||||
|
||||
while (length > 0) {
|
||||
if (length > 512) {
|
||||
MD5_Update(&c, str, 512);
|
||||
} else {
|
||||
MD5_Update(&c, str, length);
|
||||
}
|
||||
length -= 512;
|
||||
str += 512;
|
||||
}
|
||||
|
||||
MD5_Final(digest, &c);
|
||||
return digest_to_out(digest);
|
||||
}
|
||||
|
||||
/* vim: set ts=8 sw=2 et cindent: */
|
||||
|
||||
@ -36,5 +36,13 @@ int csync_unix_extensions(CSYNC *ctx);
|
||||
/* Normalize the uri to <host>/<path> */
|
||||
uint64_t csync_create_statedb_hash(CSYNC *ctx);
|
||||
|
||||
/* Calculate the md5 sum for a file given by filename.
|
||||
* Caller has to free the memory. */
|
||||
char* csync_file_md5(const char *filename);
|
||||
|
||||
/* Create an md5 sum from a data pointer with a given length.
|
||||
* Caller has to free the memory */
|
||||
char* csync_buffer_md5(const char *str, int length);
|
||||
|
||||
#endif /* _CSYNC_UTIL_H */
|
||||
/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
#include "c_time.h"
|
||||
#include "c_private.h"
|
||||
|
||||
#ifndef UNIT_TESTING
|
||||
#ifdef malloc
|
||||
#undef malloc
|
||||
#endif
|
||||
@ -44,6 +45,8 @@
|
||||
#endif
|
||||
#define calloc(x,y) DO_NOT_CALL_CALLOC__USE_C_CALLOC_INSTEAD
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef realloc
|
||||
#undef realloc
|
||||
#endif
|
||||
|
||||
@ -146,7 +146,6 @@ int csync_vio_init(CSYNC *ctx, const char *module, const char *args) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
*(void **) (&init_fn) = dlsym(ctx->module.handle, "vio_module_init");
|
||||
if ((err = dlerror()) != NULL) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "loading function failed - %s", err);
|
||||
@ -168,6 +167,26 @@ int csync_vio_init(CSYNC *ctx, const char *module, const char *args) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Useful defaults to the module capabilities */
|
||||
ctx->module.capabilities.atomar_copy_support = false;
|
||||
ctx->module.capabilities.do_post_copy_stat = true;
|
||||
ctx->module.capabilities.time_sync_required = true;
|
||||
ctx->module.capabilities.unix_extensions = -1; /* detect automatically */
|
||||
|
||||
/* Load the module capabilities from the module if it implements the it. */
|
||||
if( VIO_METHOD_HAS_FUNC(m, get_capabilities)) {
|
||||
ctx->module.capabilities = *(m->get_capabilities());
|
||||
}
|
||||
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "capabilities: atomar copy support: %s",
|
||||
ctx->module.capabilities.atomar_copy_support ? "yes": "no");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "capabilities: post copy stat: %s",
|
||||
ctx->module.capabilities.do_post_copy_stat ? "yes": "no");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "capabilities: time sync required: %s",
|
||||
ctx->module.capabilities.time_sync_required ? "yes": "no");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "capabilities: unix extensions: %d",
|
||||
ctx->module.capabilities.unix_extensions );
|
||||
|
||||
/* Some basic checks */
|
||||
if (m->method_table_size == 0) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "module %s method table size is 0", module);
|
||||
@ -184,6 +203,10 @@ int csync_vio_init(CSYNC *ctx, const char *module, const char *args) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(! VIO_METHOD_HAS_FUNC(m, get_capabilities)) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "module %s has no capabilities fn", module);
|
||||
}
|
||||
|
||||
if (! VIO_METHOD_HAS_FUNC(m, open)) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "module %s has no stat fn", module);
|
||||
return -1;
|
||||
|
||||
@ -35,10 +35,24 @@
|
||||
|
||||
typedef struct csync_vio_method_s csync_vio_method_t;
|
||||
|
||||
/* module capabilities definition.
|
||||
* remember to set useful defaults in csync_vio.c if you add something here. */
|
||||
struct csync_vio_capabilities_s {
|
||||
bool atomar_copy_support; /* set to true if the backend provides atomar copy */
|
||||
bool do_post_copy_stat; /* true if csync should check the copy afterwards */
|
||||
bool time_sync_required; /* true if local and remote need to be time synced */
|
||||
int unix_extensions; /* -1: do csync detection, 0: no unix extensions,
|
||||
1: extensions available */
|
||||
};
|
||||
|
||||
typedef struct csync_vio_capabilities_s csync_vio_capabilities_t;
|
||||
|
||||
typedef csync_vio_method_t *(*csync_vio_method_init_fn)(const char *method_name,
|
||||
const char *config_args, csync_auth_callback cb, void *userdata);
|
||||
typedef void (*csync_vio_method_finish_fn)(csync_vio_method_t *method);
|
||||
|
||||
typedef csync_vio_capabilities_t *(*csync_method_get_capabilities_fn)(void);
|
||||
|
||||
typedef csync_vio_method_handle_t *(*csync_method_open_fn)(const char *durl, int flags, mode_t mode);
|
||||
typedef csync_vio_method_handle_t *(*csync_method_creat_fn)(const char *durl, mode_t mode);
|
||||
typedef int (*csync_method_close_fn)(csync_vio_method_handle_t *fhandle);
|
||||
@ -64,6 +78,7 @@ typedef int (*csync_method_utimes_fn)(const char *uri, const struct timeval time
|
||||
|
||||
struct csync_vio_method_s {
|
||||
size_t method_table_size; /* Used for versioning */
|
||||
csync_method_get_capabilities_fn get_capabilities;
|
||||
csync_method_open_fn open;
|
||||
csync_method_creat_fn creat;
|
||||
csync_method_close_fn close;
|
||||
|
||||
@ -5,10 +5,11 @@ set(SUPPORT_LIBRARY support)
|
||||
include_directories(
|
||||
${CSYNC_PUBLIC_INCLUDE_DIRS}
|
||||
${CSTDLIB_PUBLIC_INCLUDE_DIRS}
|
||||
${CHECK_INCLUDE_DIRS}
|
||||
${CMAKE_BINARY_DIR}
|
||||
)
|
||||
|
||||
if (CHECK_FOUND)
|
||||
include_directories(${CHECK_INCLUDE_DIRS})
|
||||
# create test library
|
||||
add_library(${SUPPORT_LIBRARY} STATIC support.c cmdline.c)
|
||||
target_link_libraries(${SUPPORT_LIBRARY} ${CHECK_LIBRARIES} ${CSYNC_LIBRARY} ${CSTDLIB_LIBRARY})
|
||||
@ -51,4 +52,7 @@ macro_add_check_test(check_vio vio_tests/check_vio.c ${TEST_TARGET_LIBRARIES})
|
||||
|
||||
# sync
|
||||
macro_add_check_test(check_csync_update csync_tests/check_csync_update.c ${TEST_TARGET_LIBRARIES})
|
||||
endif (CHECK_FOUND)
|
||||
|
||||
add_subdirectory(ownCloud)
|
||||
|
||||
|
||||
1
tests/ownCloud/CMakeLists.txt
Normal file
1
tests/ownCloud/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
add_subdirectory(mocka)
|
||||
20
tests/ownCloud/mocka/CMakeLists.txt
Normal file
20
tests/ownCloud/mocka/CMakeLists.txt
Normal file
@ -0,0 +1,20 @@
|
||||
project( ocmod C )
|
||||
|
||||
add_definitions(-DUNIT_TESTING=1)
|
||||
|
||||
find_package(CMocka REQUIRED)
|
||||
|
||||
include_directories(
|
||||
${CMAKE_BINARY_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMOCKA_INCLUDE_DIRS}
|
||||
${NEON_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
|
||||
add_executable(ocmod_test ocmod_test.c)
|
||||
add_executable(md5_test md5_test.c)
|
||||
|
||||
target_link_libraries(ocmod_test ${CMOCKA_LIBRARIES} ${NEON_LIBRARIES} ${CSYNC_LIBRARY} )
|
||||
|
||||
target_link_libraries(md5_test ${CMOCKA_LIBRARIES} ${CSYNC_LIBRARY} )
|
||||
68
tests/ownCloud/mocka/md5_test.c
Normal file
68
tests/ownCloud/mocka/md5_test.c
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#define _GNU_SOURCE /* See feature_test_macros(7) */
|
||||
#include <stdio.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <setjmp.h>
|
||||
#include <iniparser.h>
|
||||
#include <std/c_path.h>
|
||||
|
||||
#include <csync_util.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
|
||||
#include "config_test.h"
|
||||
|
||||
|
||||
static void test_md5_buffer(void **state) {
|
||||
const char *t1 = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.";
|
||||
const char *t2 = "This is a nice md5 test";
|
||||
const char *t3 = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
|
||||
"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.";
|
||||
|
||||
(void) state;
|
||||
assert_string_equal( csync_buffer_md5(t1, strlen(t1)), "dbcb1ed05ecf975f532604f2d2000246");
|
||||
assert_string_equal( csync_buffer_md5(t2, strlen(t2)), "65236ae09754bca371fb869384040141");
|
||||
assert_string_equal( csync_buffer_md5(t3, strlen(t3)), "651f37892a9df60ed087bc7a1c660fec");
|
||||
}
|
||||
|
||||
static void test_md5_files(void **state) {
|
||||
char path[255];
|
||||
(void) state;
|
||||
|
||||
strcpy(path, TESTFILES_DIR);
|
||||
strcat(path, "test.txt");
|
||||
assert_string_equal( csync_file_md5(path), "f3971ce599093756e6018513d0835134");
|
||||
|
||||
strcpy(path, TESTFILES_DIR);
|
||||
strcat(path, "red_is_the_rose.jpg");
|
||||
assert_string_equal( csync_file_md5(path), "baf8eeb2a36af94f033fa0094c50c2d5");
|
||||
|
||||
}
|
||||
|
||||
|
||||
int main(void) {
|
||||
const UnitTest tests[] = {
|
||||
unit_test(test_md5_buffer),
|
||||
unit_test(test_md5_files)
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
}
|
||||
300
tests/ownCloud/mocka/ocmod_test.c
Normal file
300
tests/ownCloud/mocka/ocmod_test.c
Normal file
@ -0,0 +1,300 @@
|
||||
/*
|
||||
* Copyright 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#define _GNU_SOURCE /* See feature_test_macros(7) */
|
||||
#include <stdio.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <setjmp.h>
|
||||
#include <iniparser.h>
|
||||
#include <std/c_path.h>
|
||||
|
||||
#include "../../modules/csync_owncloud.c"
|
||||
#include <cmocka.h>
|
||||
|
||||
#include "config_test.h"
|
||||
|
||||
struct oc_credentials {
|
||||
const char *url;
|
||||
const char *user;
|
||||
const char *pwd;
|
||||
char *oc_server;
|
||||
|
||||
} _credentials;
|
||||
|
||||
|
||||
static bool load_oc_config( const char *config ) {
|
||||
dictionary *dict;
|
||||
const char* val;
|
||||
bool re = true;
|
||||
char *deflt;
|
||||
char b;
|
||||
deflt = &b;
|
||||
|
||||
|
||||
dict = iniparser_load( config );
|
||||
|
||||
if( ! dict ) {
|
||||
printf("Could not load config %s\n", config);
|
||||
return false;
|
||||
}
|
||||
|
||||
val = iniparser_getstring(dict, "global:host", deflt);
|
||||
if( val ) {
|
||||
_credentials.url = c_strdup( val );
|
||||
} else {
|
||||
re = false;
|
||||
}
|
||||
|
||||
val = iniparser_getstring(dict, "global:user", deflt);
|
||||
if( re && val ) {
|
||||
_credentials.user = c_strdup( val );
|
||||
} else {
|
||||
re = false;
|
||||
}
|
||||
|
||||
val = iniparser_getstring(dict, "global:pwd", deflt);
|
||||
if( re && val ) {
|
||||
_credentials.pwd = c_strdup( val );
|
||||
} else {
|
||||
re = false;
|
||||
}
|
||||
|
||||
if( re ) {
|
||||
asprintf(&(_credentials.oc_server),
|
||||
"owncloud://%s:%s@%s/files/webdav.php",
|
||||
_credentials.user, _credentials.pwd,
|
||||
_credentials.url );
|
||||
}
|
||||
|
||||
return re;
|
||||
}
|
||||
|
||||
|
||||
// A test case that does nothing and succeeds.
|
||||
static void null_test_success(void **state) {
|
||||
(void) state;
|
||||
}
|
||||
|
||||
|
||||
static void connect_test_success(void **state) {
|
||||
|
||||
int re = 0;
|
||||
char buf[255];
|
||||
|
||||
(void) state;
|
||||
strcpy(buf, TEST_CONFIG_DIR);
|
||||
strcat(buf, "test.cfg");
|
||||
|
||||
assert_true( load_oc_config( buf ));
|
||||
|
||||
re = dav_connect( _credentials.oc_server );
|
||||
|
||||
assert_int_equal( re, 0 );
|
||||
assert_int_equal( _connected, 1 );
|
||||
assert_int_equal( dav_session.time_delta_sum, 0);
|
||||
assert_int_equal( dav_session.time_delta_cnt, 0);
|
||||
}
|
||||
|
||||
static void fetch_a_context(void **state) {
|
||||
struct listdir_context *fetchCtx = NULL;
|
||||
char *curi = _cleanPath(_credentials.oc_server);
|
||||
int rc = 0;
|
||||
unsigned int i;
|
||||
|
||||
(void) state;
|
||||
|
||||
fetchCtx = c_malloc( sizeof( struct listdir_context ));
|
||||
fetchCtx->target = curi;
|
||||
fetchCtx->include_target = 1;
|
||||
|
||||
rc = fetch_resource_list( curi, NE_DEPTH_ONE, fetchCtx );
|
||||
assert_int_equal( rc, 0 );
|
||||
printf("Results: %d\n", fetchCtx->result_count);
|
||||
|
||||
fetchCtx->currResource = fetchCtx->list;
|
||||
for( i = 0; i < fetchCtx->result_count; i++ ) {
|
||||
assert_true( fetchCtx->currResource != NULL );
|
||||
assert_true( fetchCtx->currResource->uri != NULL );
|
||||
assert_true( fetchCtx->currResource->name != NULL );
|
||||
|
||||
printf( " %s -> %s\n", fetchCtx->currResource->uri, fetchCtx->currResource->name );
|
||||
fetchCtx->currResource = fetchCtx->currResource->next;
|
||||
}
|
||||
}
|
||||
|
||||
static int test_mkdir(const char *dir) {
|
||||
char path[255];
|
||||
|
||||
strcpy( path, _credentials.oc_server );
|
||||
strcat( path, "/");
|
||||
strcat( path, dir );
|
||||
|
||||
return owncloud_mkdir( path, 775 );
|
||||
}
|
||||
|
||||
static void setup_toplevel_dir( void **state ) {
|
||||
char basepath[255];
|
||||
|
||||
strcpy( basepath, "tXXXXXX");
|
||||
assert_int_equal( c_tmpname(basepath), 0 );
|
||||
printf("Using top testing dir %s\n", basepath);
|
||||
assert_int_equal( test_mkdir( basepath ), 0 );
|
||||
*state = (void*) c_strdup(basepath);
|
||||
}
|
||||
|
||||
static void teardown_toplevel_dir( void **state ) {
|
||||
(void) state;
|
||||
}
|
||||
|
||||
static void stat_local_file( csync_stat_t *sb, const char *file )
|
||||
{
|
||||
const _TCHAR *mpath = NULL;
|
||||
mpath = c_multibyte(file);
|
||||
assert_int_not_equal(_tstat(mpath, sb), -1);
|
||||
c_free_multibyte(mpath);
|
||||
}
|
||||
|
||||
#define BUFSIZE 4096
|
||||
static size_t upload_a_file( void **state, const char *src_name, const char *durl ) {
|
||||
|
||||
char buffer[BUFSIZE+1];
|
||||
int size;
|
||||
char path[256];
|
||||
char src_path[256];
|
||||
int fh;
|
||||
csync_vio_method_handle_t *handle;
|
||||
size_t written;
|
||||
size_t overall_size = 0;
|
||||
csync_stat_t sb;
|
||||
|
||||
/* Create the target path */
|
||||
strcpy( path, _credentials.oc_server );
|
||||
strcat( path, "/");
|
||||
strcat( path, (const char*) *state );
|
||||
strcat( path, "/");
|
||||
strcat( path, durl );
|
||||
|
||||
handle = owncloud_creat( path, 0644 );
|
||||
assert_int_not_equal( handle, NULL );
|
||||
|
||||
strcpy(src_path, TESTFILES_DIR);
|
||||
strcat(src_path, src_name);
|
||||
fh = open(src_path, O_RDONLY);
|
||||
assert_int_not_equal( fh, -1 );
|
||||
|
||||
while( (size = read(fh, buffer, BUFSIZE) )>0 ) {
|
||||
buffer[size] = '\0';
|
||||
written = owncloud_write( handle, buffer, size );
|
||||
assert_int_equal( size, written );
|
||||
overall_size += written;
|
||||
}
|
||||
assert_int_equal( owncloud_close(handle), 0);
|
||||
|
||||
/* stat the local file */
|
||||
stat_local_file( &sb, src_path );
|
||||
|
||||
assert_int_equal( overall_size, sb.st_size );
|
||||
|
||||
close(fh);
|
||||
|
||||
return overall_size;
|
||||
}
|
||||
|
||||
static void test_upload_files( void **state ) {
|
||||
const char *bpath = (char*) (*state);
|
||||
|
||||
upload_a_file( state, "test.txt", "t1/test.txt");
|
||||
upload_a_file( state, "red_is_the_rose.jpg", "t1/red is the rose.jpg");
|
||||
|
||||
printf("Base path: %s\n", bpath);
|
||||
|
||||
}
|
||||
|
||||
static void download_a_file( const char* local, void **state, const char *durl)
|
||||
{
|
||||
char buffer[BUFSIZE+1];
|
||||
char path[256];
|
||||
char local_path[256];
|
||||
|
||||
csync_vio_method_handle_t *handle;
|
||||
size_t count;
|
||||
size_t overall_size = 0;
|
||||
csync_stat_t sb;
|
||||
|
||||
/* Create the target path */
|
||||
strcpy( path, _credentials.oc_server );
|
||||
strcat( path, "/");
|
||||
strcat( path, (const char*) *state );
|
||||
strcat( path, "/");
|
||||
strcat( path, durl );
|
||||
|
||||
handle = owncloud_open( path, O_RDONLY, 0644 );
|
||||
assert_int_not_equal( handle, NULL );
|
||||
|
||||
while( (count = owncloud_read(handle, buffer, BUFSIZE)) > 0 ) {
|
||||
overall_size += count;
|
||||
}
|
||||
assert_int_equal( owncloud_close(handle), 0 );
|
||||
|
||||
strcpy(local_path, TESTFILES_DIR);
|
||||
strcat(local_path, local);
|
||||
stat_local_file( &sb, local_path );
|
||||
|
||||
/* assert the download size, it has to be the same. */
|
||||
assert_int_equal( overall_size, sb.st_size );
|
||||
|
||||
}
|
||||
|
||||
static void test_download_files( void **state ) {
|
||||
const char *bpath = (char*) (*state);
|
||||
|
||||
printf("Base path: %s\n", bpath);
|
||||
|
||||
download_a_file( "test.txt", state, "t1/test.txt");
|
||||
download_a_file( "red_is_the_rose.jpg", state, "t1/red is the rose.jpg");
|
||||
}
|
||||
|
||||
static void test_setup_dirs(void **state) {
|
||||
const char *basepath = *state;
|
||||
char path[255];
|
||||
|
||||
strcpy( path, basepath );
|
||||
strcat( path, "/t1" );
|
||||
assert_int_equal( test_mkdir( path ), 0 );
|
||||
|
||||
strcpy( path, basepath );
|
||||
strcat( path, "/t2");
|
||||
assert_int_equal( test_mkdir( path ), 0 );
|
||||
strcat( path, "/Übergröße");
|
||||
assert_int_equal( test_mkdir( path ), 0 );
|
||||
}
|
||||
|
||||
|
||||
int main(void) {
|
||||
const UnitTest tests[] = {
|
||||
unit_test(null_test_success),
|
||||
unit_test(connect_test_success),
|
||||
unit_test(fetch_a_context),
|
||||
unit_test_setup_teardown(test_setup_dirs, setup_toplevel_dir, teardown_toplevel_dir),
|
||||
unit_test(test_upload_files),
|
||||
unit_test(test_download_files),
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user