Merge remote-tracking branch 'freitag/dav' into davbf

This commit is contained in:
Olivier Goffart 2013-03-02 13:43:59 +01:00
commit 0906312c02
17 changed files with 127 additions and 46 deletions

View file

@ -8,7 +8,7 @@ set(APPLICATION_NAME ${PROJECT_NAME})
set(APPLICATION_VERSION_MAJOR "0")
set(APPLICATION_VERSION_MINOR "70")
set(APPLICATION_VERSION_PATCH "3")
set(APPLICATION_VERSION_PATCH "4")
set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}")

View file

@ -13,7 +13,7 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING")
### versions
set(CPACK_PACKAGE_VERSION_MAJOR "0")
set(CPACK_PACKAGE_VERSION_MINOR "70")
set(CPACK_PACKAGE_VERSION_PATCH "3")
set(CPACK_PACKAGE_VERSION_PATCH "4")
set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
set(CPACK_GENERATOR "TGZ")

View file

@ -49,7 +49,11 @@ mark_as_advanced(NEON_INCLUDE_DIRS NEON_LIBRARIES)
# be defined in the owncloud module.
# If neon was not compiled with LFS its also ok since the underlying system
# than probably supports large files anyway.
FIND_PROGRAM( NEON_CONFIG_EXECUTABLE NAMES neon-config )
IF( CMAKE_FIND_ROOT_PATH )
FIND_PROGRAM( NEON_CONFIG_EXECUTABLE NAMES neon-config HINTS ${CMAKE_FIND_ROOT_PATH}/bin )
ELSE( CMAKE_FIND_ROOT_PATH )
FIND_PROGRAM( NEON_CONFIG_EXECUTABLE NAMES neon-config )
ENDIF( CMAKE_FIND_ROOT_PATH )
IF ( NEON_CONFIG_EXECUTABLE )
MESSAGE(STATUS "neon-config executable: ${NEON_CONFIG_EXECUTABLE}")

View file

@ -9,3 +9,6 @@ max_depth = 50
# NOT IN USE:
# sync symbolic links if the remote filesystem supports it.
#sync_symbolic_links = false
# connection timeout in seconds
timeout = 30

View file

@ -571,6 +571,9 @@ static void post_request_hook(ne_request *req, void *userdata, const ne_status *
(void) userdata;
if (dav_session.session_key)
return; /* We already have a session cookie, and we should ignore other ones */
if(!(status && req)) return;
if( status->klass == 2 || status->code == 401 ) {
/* successful request */
@ -599,10 +602,17 @@ static void post_request_hook(ne_request *req, void *userdata, const ne_status *
} else if( *sc_end == ';' ) {
/* We are at the end of the session key. */
int keylen = sc_end-sc_val;
if( key ) SAFE_FREE(key);
key = c_malloc(keylen+1);
strncpy( key, sc_val, keylen );
key[keylen] = '\0';
if( key ) {
int oldlen = strlen(key);
key = c_realloc(key, oldlen + 2 + keylen+1);
strcpy(key + oldlen, "; ");
strncpy(key + oldlen + 2, sc_val, keylen);
key[oldlen + 2 + keylen] = '\0';
} else {
key = c_malloc(keylen+1);
strncpy( key, sc_val, keylen );
key[keylen] = '\0';
}
/* now search for a ',' to find a potential other header entry */
while(cnt < len && *sc_end != ',') {
@ -1030,10 +1040,18 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
*/
content_type = ne_get_response_header( request, "Content-Type" );
if( !(content_type && c_streq(content_type, "application/xml; charset=utf-8") ) ) {
ssize_t resp_size;
char buffer[4096];
ZERO_STRUCT(buffer);
DEBUG_WEBDAV("ERROR: Content type of propfind request not XML: %s.",
content_type ? content_type: "<empty>");
errno = ERRNO_WRONG_CONTENT;
set_error_message("Server error: PROPFIND reply is not XML formatted!");
/* Read the response buffer to log the actual problem. */
resp_size = ne_read_response_block(request, buffer, 4095);
DEBUG_WEBDAV("ERROR: Content was of size %ld: %s", resp_size, buffer );
ret = NE_CONNECT;
}
}
@ -1055,17 +1073,17 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
/* 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 %llu", (unsigned long long) time_diff );
DEBUG_WEBDAV( "The first time_delta is %ld", 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");
// errno = ERRNO_TIMEDELTA;
// ret = OC_TIMEDELTA_FAIL;
} else {
DEBUG_WEBDAV("Ok: Time delta remained (almost) the same: %llu.", (unsigned long long) time_diff);
DEBUG_WEBDAV("Ok: Time delta remained (almost) the same: %ld.", time_diff);
}
} else {
DEBUG_WEBDAV("Difference to last server time delta: %llu", (unsigned long long) time_diff_delta );
DEBUG_WEBDAV("Difference to last server time delta: %ld", time_diff_delta );
}
dav_session.time_delta = time_diff;
} else {
@ -1108,6 +1126,24 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
return fetchCtx;
}
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(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. */
if( errno != ERRNO_WRONG_CONTENT ) break;
DEBUG_WEBDAV("=> Errno after fetch resource list for %s: %d", uri, errno);
DEBUG_WEBDAV(" New attempt %i", i);
}
return fetchCtx;
}
/*
* helper: convert a resource struct to file_stat struct.
*/
@ -1236,7 +1272,8 @@ static int owncloud_stat(const char *uri, csync_vio_file_stat_t *buf) {
}
/* fetch data via a propfind call. */
fetchCtx = fetch_resource_list( uri, NE_DEPTH_ONE);
/* 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;
@ -1374,7 +1411,7 @@ static char*_lastDir = NULL;
* int unix_extensions - oC supports unix extensions.
* bool propagate_on_fd - oC supports the send_file method.
*/
static csync_vio_capabilities_t _owncloud_capabilities = { true, false, false, 1, true };
static csync_vio_capabilities_t _owncloud_capabilities = { true, false, false, 0, true };
static csync_vio_capabilities_t *owncloud_capabilities(void)
{
@ -1808,7 +1845,8 @@ static csync_vio_method_handle_t *owncloud_opendir(const char *uri) {
dav_connect( uri );
fetchCtx = fetch_resource_list( uri, NE_DEPTH_ONE );
/* fetchCtx = fetch_resource_list( 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);
@ -1874,7 +1912,6 @@ static csync_vio_file_stat_t *owncloud_readdir(csync_vio_method_handle_t *dhandl
static int owncloud_mkdir(const char *uri, mode_t mode) {
int rc = NE_OK;
int len = 0;
ne_request *req = NULL;
char *path = _cleanPath( uri );
(void) mode; /* unused */
@ -1898,16 +1935,12 @@ static int owncloud_mkdir(const char *uri, mode_t mode) {
}
DEBUG_WEBDAV("MKdir on %s", path );
req = ne_request_create(dav_session.ctx, "MKCOL", path);
rc = ne_simple_request(dav_session.ctx, req);
rc = ne_mkcol(dav_session.ctx, path );
set_errno_from_neon_errcode(rc);
/* Special for mkcol: it returns 405 if the directory already exists.
* To keep csync vio_mkdirs working errno EEXIST has to be returned. */
if( ne_get_status(req)->code == 405 ) {
if (errno == EPERM && http_result_code_from_session() == 405)
errno = EEXIST;
} else {
set_errno_from_neon_errcode(rc);
}
}
SAFE_FREE( path );
@ -2083,7 +2116,7 @@ static int owncloud_set_property(const char *key, void *data) {
_progresscb = *(csync_progress_callback*)(data);
return 0;
}
if (c_streq(key, "read_timeout")) {
if (c_streq(key, "read_timeout") || c_streq(key, "timeout")) {
dav_session.read_timeout = *(int*)(data);
return 0;
}

View file

@ -304,7 +304,7 @@ static int _sftp_connect(const char *uri) {
break;
case SSH_SERVER_FOUND_OTHER:
fprintf(stderr, "csync_sftp - the host key for this server was not "
"found but an other type of key exists.\n");
"found but another type of key exists.\n");
fprintf(stderr, "csync_sftp - an attacker might change the default "
"server key to confuse your client into thinking the key does not "
"exist\n");

View file

@ -332,6 +332,9 @@ retry_vio_init:
if (ctx->callbacks.progresscb)
csync_vio_set_property(ctx, "progress_callback", &ctx->callbacks.progresscb);
if (ctx->options.timeout)
csync_vio_set_property(ctx, "timeout", &ctx->options.timeout);
if (c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp) < 0) {
ctx->error_code = CSYNC_ERR_TREE;
rc = -1;

View file

@ -51,7 +51,7 @@ extern "C" {
/* csync version */
#define LIBCSYNC_VERSION_MAJOR 0
#define LIBCSYNC_VERSION_MINOR 70
#define LIBCSYNC_VERSION_MICRO 3
#define LIBCSYNC_VERSION_MICRO 4
#define LIBCSYNC_VERSION_INT CSYNC_VERSION_INT(LIBCSYNC_VERSION_MAJOR, \
LIBCSYNC_VERSION_MINOR, \

View file

@ -144,6 +144,10 @@ int csync_config_load(CSYNC *ctx, const char *config) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Config: sync_symbolic_links = %d",
ctx->options.sync_symbolic_links);
ctx->options.timeout = iniparser_getint(dict, "global:timeout", 0);
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Config: timeout = %d",
ctx->options.timeout);
iniparser_freedict(dict);
return 0;

View file

@ -125,6 +125,9 @@ csync_vio_method_handle_t *csync_dbtree_opendir(CSYNC *ctx, const char *name)
}
if( cnt < tpath_len ) continue;
if (!list->vector[base+8][0])
continue; /* If md5 is empty, the file was removed on the server */
fs = csync_vio_file_stat_new();
fs->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE;

View file

@ -132,6 +132,7 @@ struct csync_s {
bool local_only_mode;
bool remote_push_atomar;
int log_verbosity;
int timeout;
#ifdef WITH_ICONV
iconv_t iconv_cd;
#endif

View file

@ -1037,6 +1037,27 @@ out:
return rc;
}
/* If a remove operation failed, we need to update the st so the information
that will be stored in the database will make it so that we try to remove
again on the next sync. */
static void _csync_remove_error(CSYNC *ctx, csync_file_stat_t *st, char *uri) {
/* Write it back to statedb, that we try to delete it next time. */
st->instruction = CSYNC_INSTRUCTION_NONE;
if (ctx->replica == LOCAL_REPLICA) {
/* Update the mtime */
csync_vio_file_stat_t* vst = csync_vio_file_stat_new();
if (csync_vio_stat(ctx, uri, vst) == 0) {
st->inode = vst->inode;
st->modtime = vst->mtime;
}
csync_vio_file_stat_destroy(vst);
/* don't write the md5 to the database */
SAFE_FREE(st->md5);
}
}
static int _csync_remove_dir(CSYNC *ctx, csync_file_stat_t *st) {
c_list_t *list = NULL;
char errbuf[256] = {0};
@ -1108,13 +1129,13 @@ static int _csync_remove_dir(CSYNC *ctx, csync_file_stat_t *st) {
rc = 0;
out:
SAFE_FREE(uri);
/* set instruction for the statedb merger */
if (rc != 0) {
st->instruction = CSYNC_INSTRUCTION_NONE;
_csync_remove_error(ctx, st, uri);
}
SAFE_FREE(uri);
return rc;
}
@ -1310,8 +1331,7 @@ static int _csync_propagation_cleanup(CSYNC *ctx) {
}
if (csync_vio_rmdir(ctx, dir) < 0) {
/* Write it back to statedb, that we try to delete it next time. */
st->instruction = CSYNC_INSTRUCTION_NONE;
_csync_remove_error(ctx, st, uri);
} else {
st->instruction = CSYNC_INSTRUCTION_DELETED;
}

View file

@ -142,9 +142,6 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
switch (other->instruction) {
/* file on other replica is new too */
case CSYNC_INSTRUCTION_NEW:
/* if (cur->modtime > other->modtime) { */
CSYNC_LOG( CSYNC_LOG_PRIORITY_DEBUG, "** size compare: %lld <-> %lld", (long long) cur->size,
(long long) other->size);
if(cur->modtime - other->modtime > ACCEPTED_TIME_DIFF) {
if( other->size == cur->size &&
_time_dst_off( cur->modtime, other->modtime, ONE_HOUR ) ) {
@ -164,8 +161,6 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
other->instruction = CSYNC_INSTRUCTION_NONE;
}
}
/* } else if (cur->modtime < other->modtime) { */
} else if (other->modtime - cur->modtime > ACCEPTED_TIME_DIFF) {
/* Check if we have the dst problem. Older versions of ocsync wrote a wrong
* (ie. localized) mtime to the files which can be ignored if the size is equal

View file

@ -26,6 +26,7 @@ int c_mkdirs(const char *path, mode_t mode) {
if (_tstat(wpath, &sb) == 0) {
if (! S_ISDIR(sb.st_mode)) {
errno = ENOTDIR;
c_free_multibyte(wpath);
return -1;
}
}
@ -43,13 +44,17 @@ int c_mkdirs(const char *path, mode_t mode) {
if (_tstat(swpath, &sb) == 0) {
if (! S_ISDIR(sb.st_mode)) {
errno = ENOTDIR;
c_free_multibyte(swpath);
c_free_multibyte(wpath);
return -1;
}
} else if (errno != ENOENT) {
c_free_multibyte(swpath);
c_free_multibyte(wpath);
return -1;
} else if (c_mkdirs(subpath, mode) < 0) {
c_free_multibyte(swpath);
c_free_multibyte(wpath);
return -1;
}
}
@ -74,7 +79,8 @@ int c_rmdirs(const char *path) {
char *fname = NULL;
_TCHAR *wfname = NULL;
_TCHAR *wpath = c_multibyte(path);
char *rd_name = NULL;
if ((d = _topendir(wpath)) != NULL) {
while( _tstat(wpath, &sb) == 0) {
/* if we can remove the directory we're done */
@ -87,27 +93,30 @@ int c_rmdirs(const char *path) {
case EBADF:
break; /* continue */
default:
c_free_multibyte(wpath);
_tclosedir(d);
return 0;
}
while ((dp = _treaddir(d)) != NULL) {
size_t len;
rd_name = c_utf8(dp->d_name);
/* skip '.' and '..' */
if (dp->d_name[0] == '.' &&
(dp->d_name[1] == '\0' ||
(dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) {
continue;
if( c_streq( rd_name, "." ) || c_streq( rd_name, ".." ) ) {
c_free_utf8(rd_name);
continue;
}
len = strlen(path) + _tcslen(dp->d_name) + 2;
len = strlen(path) + strlen(rd_name) + 2;
fname = c_malloc(len);
if (fname == NULL) {
c_free_multibyte(wpath);
c_free_utf8(rd_name);
_tclosedir(d);
return -1;
}
snprintf(fname, len, "%s/%s", path, dp->d_name);
wfname = c_multibyte(fname);
snprintf(fname, len, "%s/%s", path, rd_name);
wfname = c_multibyte(fname);
/* stat the file */
if (_tstat(wfname, &sb) != -1) {
@ -120,7 +129,9 @@ int c_rmdirs(const char *path) {
if (errno == EACCES) {
_tclosedir(d);
SAFE_FREE(fname);
c_free_multibyte(wfname);
c_free_multibyte(wpath);
c_free_multibyte(wfname);
c_free_utf8(rd_name);
return -1;
}
c_rmdirs(fname);
@ -130,7 +141,8 @@ int c_rmdirs(const char *path) {
}
} /* lstat */
SAFE_FREE(fname);
c_free_multibyte(wfname);
c_free_multibyte(wfname);
c_free_utf8(rd_name);
} /* readdir */
_trewinddir(d);
@ -138,6 +150,7 @@ int c_rmdirs(const char *path) {
} else {
return -1;
}
c_free_multibyte(wpath);
_tclosedir(d);
return 0;

View file

@ -77,7 +77,6 @@ typedef struct stat csync_stat_t;
#if defined _WIN32 && defined _UNICODE
typedef wchar_t _TCHAR;
#define _tcslen wcslen
#define _topen _wopen
#define _tdirent _wdirent
#define _TDIR _WDIR
@ -97,7 +96,6 @@ typedef wchar_t _TCHAR;
#else
typedef char _TCHAR;
#define _tdirent dirent
#define _tcslen strlen
#define _topen open
#define _TDIR DIR
#define _topendir opendir

View file

@ -281,7 +281,7 @@ char* c_utf8(const _TCHAR *wstr)
char *dst = NULL;
#ifdef _WIN32
if(!wstr) return NULL;
size_t len = _tcslen( wstr );
size_t len = wcslen( wstr );
/* Call once to get the required size. */
int size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr, len, NULL, 0, NULL, NULL);
if( size_needed > 0 ) {

View file

@ -361,6 +361,10 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
if( h == INVALID_HANDLE_VALUE ) {
DWORD err = GetLastError();
/* CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "ERR: Failed to create a handle for %s: %ld", uri,err ); */
csync_vio_file_stat_destroy(buf);
c_free_multibyte(wuri);
return -1;
} else {
FILETIME ftCreate, ftAccess, ftWrite;
SYSTEMTIME stUTC;