mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-25 22:46:04 +03:00
Merge pull request #1839 from owncloud/directDownload
Direct download URL support + global variable refactoring Reviewed offline by @dragotin
This commit is contained in:
commit
06863ca9c6
22 changed files with 689 additions and 783 deletions
|
@ -191,7 +191,7 @@ int csync_init(CSYNC *ctx) {
|
||||||
ctx->local.type = LOCAL_REPLICA;
|
ctx->local.type = LOCAL_REPLICA;
|
||||||
|
|
||||||
if ( !ctx->options.local_only_mode) {
|
if ( !ctx->options.local_only_mode) {
|
||||||
owncloud_init(csync_get_userdata(ctx));
|
owncloud_init(ctx);
|
||||||
ctx->remote.type = REMOTE_REPLICA;
|
ctx->remote.type = REMOTE_REPLICA;
|
||||||
} else {
|
} else {
|
||||||
ctx->remote.type = LOCAL_REPLICA;
|
ctx->remote.type = LOCAL_REPLICA;
|
||||||
|
@ -211,8 +211,6 @@ int csync_init(CSYNC *ctx) {
|
||||||
|
|
||||||
ctx->status = CSYNC_STATUS_INIT;
|
ctx->status = CSYNC_STATUS_INIT;
|
||||||
|
|
||||||
csync_set_module_property(ctx, "csync_context", ctx);
|
|
||||||
|
|
||||||
/* initialize random generator */
|
/* initialize random generator */
|
||||||
srand(time(NULL));
|
srand(time(NULL));
|
||||||
|
|
||||||
|
@ -444,6 +442,8 @@ static int _csync_treewalk_visitor(void *obj, void *data) {
|
||||||
trav.rename_path = cur->destpath;
|
trav.rename_path = cur->destpath;
|
||||||
trav.etag = cur->etag;
|
trav.etag = cur->etag;
|
||||||
trav.file_id = cur->file_id;
|
trav.file_id = cur->file_id;
|
||||||
|
trav.directDownloadUrl = cur->directDownloadUrl;
|
||||||
|
trav.directDownloadCookies = cur->directDownloadCookies;
|
||||||
trav.inode = cur->inode;
|
trav.inode = cur->inode;
|
||||||
|
|
||||||
trav.error_status = cur->error_status;
|
trav.error_status = cur->error_status;
|
||||||
|
@ -466,7 +466,7 @@ static int _csync_treewalk_visitor(void *obj, void *data) {
|
||||||
|
|
||||||
rc = (*visitor)(&trav, twctx->userdata);
|
rc = (*visitor)(&trav, twctx->userdata);
|
||||||
cur->instruction = trav.instruction;
|
cur->instruction = trav.instruction;
|
||||||
if (trav.etag != cur->etag) {
|
if (trav.etag != cur->etag) { // FIXME It would be nice to have this documented
|
||||||
SAFE_FREE(cur->etag);
|
SAFE_FREE(cur->etag);
|
||||||
cur->etag = c_strdup(trav.etag);
|
cur->etag = c_strdup(trav.etag);
|
||||||
}
|
}
|
||||||
|
@ -617,7 +617,7 @@ int csync_commit(CSYNC *ctx) {
|
||||||
}
|
}
|
||||||
ctx->statedb.db = NULL;
|
ctx->statedb.db = NULL;
|
||||||
|
|
||||||
rc = csync_vio_commit(ctx);
|
rc = owncloud_commit(ctx);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "commit failed: %s",
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "commit failed: %s",
|
||||||
ctx->error_string ? ctx->error_string : "");
|
ctx->error_string ? ctx->error_string : "");
|
||||||
|
@ -679,6 +679,8 @@ int csync_destroy(CSYNC *ctx) {
|
||||||
SAFE_FREE(ctx->options.config_dir);
|
SAFE_FREE(ctx->options.config_dir);
|
||||||
SAFE_FREE(ctx->error_string);
|
SAFE_FREE(ctx->error_string);
|
||||||
|
|
||||||
|
owncloud_destroy(ctx);
|
||||||
|
|
||||||
#ifdef WITH_ICONV
|
#ifdef WITH_ICONV
|
||||||
c_close_iconv();
|
c_close_iconv();
|
||||||
#endif
|
#endif
|
||||||
|
@ -912,6 +914,8 @@ int csync_abort_requested(CSYNC *ctx)
|
||||||
void csync_file_stat_free(csync_file_stat_t *st)
|
void csync_file_stat_free(csync_file_stat_t *st)
|
||||||
{
|
{
|
||||||
if (st) {
|
if (st) {
|
||||||
|
SAFE_FREE(st->directDownloadUrl);
|
||||||
|
SAFE_FREE(st->directDownloadCookies);
|
||||||
SAFE_FREE(st->etag);
|
SAFE_FREE(st->etag);
|
||||||
SAFE_FREE(st->destpath);
|
SAFE_FREE(st->destpath);
|
||||||
SAFE_FREE(st);
|
SAFE_FREE(st);
|
||||||
|
@ -920,7 +924,7 @@ void csync_file_stat_free(csync_file_stat_t *st)
|
||||||
|
|
||||||
int csync_set_module_property(CSYNC* ctx, const char* key, void* value)
|
int csync_set_module_property(CSYNC* ctx, const char* key, void* value)
|
||||||
{
|
{
|
||||||
return csync_vio_set_property(ctx, key, value);
|
return owncloud_set_property(ctx, key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -189,6 +189,8 @@ struct csync_tree_walk_file_s {
|
||||||
const char *rename_path;
|
const char *rename_path;
|
||||||
const char *etag;
|
const char *etag;
|
||||||
const char *file_id;
|
const char *file_id;
|
||||||
|
char *directDownloadUrl;
|
||||||
|
char *directDownloadCookies;
|
||||||
struct {
|
struct {
|
||||||
int64_t size;
|
int64_t size;
|
||||||
time_t modtime;
|
time_t modtime;
|
||||||
|
|
|
@ -20,79 +20,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "csync_owncloud.h"
|
#include "csync_owncloud.h"
|
||||||
|
#include "csync_owncloud_private.h"
|
||||||
|
|
||||||
#include <inttypes.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
|
* helper method to build up a user text for SSL problems, called from the
|
||||||
|
@ -116,7 +47,7 @@ static void addSSLWarning( char *ptr, const char *warn, int len )
|
||||||
* it to the csync callback to ask the user.
|
* it to the csync callback to ask the user.
|
||||||
*/
|
*/
|
||||||
#define LEN 4096
|
#define LEN 4096
|
||||||
static int verify_sslcert(void *userdata, int failures,
|
static int ssl_callback_by_neon(void *userdata, int failures,
|
||||||
const ne_ssl_certificate *certificate)
|
const ne_ssl_certificate *certificate)
|
||||||
{
|
{
|
||||||
char problem[LEN];
|
char problem[LEN];
|
||||||
|
@ -124,8 +55,8 @@ static int verify_sslcert(void *userdata, int failures,
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
const ne_ssl_certificate *cert = certificate;
|
const ne_ssl_certificate *cert = certificate;
|
||||||
csync_auth_callback authcb = NULL;
|
csync_auth_callback authcb = NULL;
|
||||||
|
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
|
||||||
|
|
||||||
(void) userdata;
|
|
||||||
memset( problem, 0, LEN );
|
memset( problem, 0, LEN );
|
||||||
|
|
||||||
while( cert ) {
|
while( cert ) {
|
||||||
|
@ -161,14 +92,14 @@ static int verify_sslcert(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 );
|
addSSLWarning( problem, "Do you want to accept the certificate chain anyway?\nAnswer yes to do so and take the risk: ", LEN );
|
||||||
|
|
||||||
if( dav_session.csync_ctx ) {
|
if( ctx->csync_ctx ) {
|
||||||
authcb = csync_get_auth_callback( dav_session.csync_ctx );
|
authcb = csync_get_auth_callback( ctx->csync_ctx );
|
||||||
}
|
}
|
||||||
if( authcb ){
|
if( authcb ){
|
||||||
/* call the csync callback */
|
/* call the csync callback */
|
||||||
DEBUG_WEBDAV("Call the csync callback for SSL problems");
|
DEBUG_WEBDAV("Call the csync callback for SSL problems");
|
||||||
memset( buf, 0, NE_ABUFSIZ );
|
memset( buf, 0, NE_ABUFSIZ );
|
||||||
(*authcb) ( problem, buf, NE_ABUFSIZ-1, 1, 0, _userdata );
|
(*authcb) ( problem, buf, NE_ABUFSIZ-1, 1, 0, csync_get_userdata(ctx->csync_ctx) );
|
||||||
if( buf[0] == 'y' || buf[0] == 'Y') {
|
if( buf[0] == 'y' || buf[0] == 'Y') {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -184,41 +115,39 @@ static int verify_sslcert(void *userdata, int failures,
|
||||||
* Authentication callback. Is set by ne_set_server_auth to be called
|
* Authentication callback. Is set by ne_set_server_auth to be called
|
||||||
* from the neon lib to authenticate a request.
|
* from the neon lib to authenticate a request.
|
||||||
*/
|
*/
|
||||||
static int ne_auth( void *userdata, const char *realm, int attempt,
|
static int authentication_callback_by_neon( void *userdata, const char *realm, int attempt,
|
||||||
char *username, char *password)
|
char *username, char *password)
|
||||||
{
|
{
|
||||||
char buf[NE_ABUFSIZ];
|
char buf[NE_ABUFSIZ];
|
||||||
csync_auth_callback authcb = NULL;
|
csync_auth_callback authcb = NULL;
|
||||||
int re = attempt;
|
int re = attempt;
|
||||||
|
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
|
||||||
|
|
||||||
(void) userdata;
|
|
||||||
(void) realm;
|
(void) realm;
|
||||||
|
|
||||||
/* DEBUG_WEBDAV( "Authentication required %s", realm ); */
|
/* DEBUG_WEBDAV( "Authentication required %s", realm ); */
|
||||||
if( username && password ) {
|
if( username && password ) {
|
||||||
DEBUG_WEBDAV( "Authentication required %s", username );
|
DEBUG_WEBDAV( "Authentication required %s", username );
|
||||||
if( dav_session.user ) {
|
if( ctx->dav_session.user ) {
|
||||||
/* allow user without password */
|
/* allow user without password */
|
||||||
if( strlen( dav_session.user ) < NE_ABUFSIZ ) {
|
if( strlen( ctx->dav_session.user ) < NE_ABUFSIZ ) {
|
||||||
strcpy( username, dav_session.user );
|
strcpy( username, ctx->dav_session.user );
|
||||||
}
|
}
|
||||||
if( dav_session.pwd && strlen( dav_session.pwd ) < NE_ABUFSIZ ) {
|
if( ctx->dav_session.pwd && strlen( ctx->dav_session.pwd ) < NE_ABUFSIZ ) {
|
||||||
strcpy( password, dav_session.pwd );
|
strcpy( password, ctx->dav_session.pwd );
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if( dav_session.csync_ctx ) {
|
authcb = csync_get_auth_callback( ctx->csync_ctx );
|
||||||
authcb = csync_get_auth_callback( dav_session.csync_ctx );
|
|
||||||
}
|
|
||||||
if( authcb != NULL ){
|
if( authcb != NULL ){
|
||||||
/* call the csync callback */
|
/* call the csync callback */
|
||||||
DEBUG_WEBDAV("Call the csync callback for %s", realm );
|
DEBUG_WEBDAV("Call the csync callback for %s", realm );
|
||||||
memset( buf, 0, NE_ABUFSIZ );
|
memset( buf, 0, NE_ABUFSIZ );
|
||||||
(*authcb) ("Enter your username: ", buf, NE_ABUFSIZ-1, 1, 0, _userdata );
|
(*authcb) ("Enter your username: ", buf, NE_ABUFSIZ-1, 1, 0, csync_get_userdata(ctx->csync_ctx) );
|
||||||
if( strlen(buf) < NE_ABUFSIZ ) {
|
if( strlen(buf) < NE_ABUFSIZ ) {
|
||||||
strcpy( username, buf );
|
strcpy( username, buf );
|
||||||
}
|
}
|
||||||
memset( buf, 0, NE_ABUFSIZ );
|
memset( buf, 0, NE_ABUFSIZ );
|
||||||
(*authcb) ("Enter your password: ", buf, NE_ABUFSIZ-1, 0, 0, _userdata );
|
(*authcb) ("Enter your password: ", buf, NE_ABUFSIZ-1, 0, 0, csync_get_userdata(ctx->csync_ctx) );
|
||||||
if( strlen(buf) < NE_ABUFSIZ) {
|
if( strlen(buf) < NE_ABUFSIZ) {
|
||||||
strcpy( password, buf );
|
strcpy( password, buf );
|
||||||
}
|
}
|
||||||
|
@ -235,15 +164,15 @@ static int ne_auth( void *userdata, const char *realm, int attempt,
|
||||||
* from the neon lib to authenticate against a proxy. The data to authenticate
|
* from the neon lib to authenticate against a proxy. The data to authenticate
|
||||||
* against comes from mirall throught vio_module_init function.
|
* against comes from mirall throught vio_module_init function.
|
||||||
*/
|
*/
|
||||||
static int ne_proxy_auth( void *userdata, const char *realm, int attempt,
|
static int proxy_authentication_callback_by_neon( void *userdata, const char *realm, int attempt,
|
||||||
char *username, char *password)
|
char *username, char *password)
|
||||||
{
|
{
|
||||||
(void) userdata;
|
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
|
||||||
(void) realm;
|
(void) realm;
|
||||||
if( dav_session.proxy_user && strlen( dav_session.proxy_user ) < NE_ABUFSIZ) {
|
if( ctx->dav_session.proxy_user && strlen( ctx->dav_session.proxy_user ) < NE_ABUFSIZ) {
|
||||||
strcpy( username, dav_session.proxy_user );
|
strcpy( username, ctx->dav_session.proxy_user );
|
||||||
if( dav_session.proxy_pwd && strlen( dav_session.proxy_pwd ) < NE_ABUFSIZ) {
|
if( ctx->dav_session.proxy_pwd && strlen( ctx->dav_session.proxy_pwd ) < NE_ABUFSIZ) {
|
||||||
strcpy( password, dav_session.proxy_pwd );
|
strcpy( password, ctx->dav_session.proxy_pwd );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* NTLM needs several attempts */
|
/* NTLM needs several attempts */
|
||||||
|
@ -251,42 +180,42 @@ static int ne_proxy_auth( void *userdata, const char *realm, int attempt,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Configure the proxy depending on the variables */
|
/* Configure the proxy depending on the variables */
|
||||||
static int configureProxy( ne_session *session )
|
static int configureProxy( csync_owncloud_ctx_t *ctx, ne_session *session )
|
||||||
{
|
{
|
||||||
int port = 8080;
|
int port = 8080;
|
||||||
int re = -1;
|
int re = -1;
|
||||||
|
|
||||||
if( ! session ) return -1;
|
if( ! session ) return -1;
|
||||||
if( ! dav_session.proxy_type ) return 0; /* Go by NoProxy per default */
|
if( ! ctx->dav_session.proxy_type ) return 0; /* Go by NoProxy per default */
|
||||||
|
|
||||||
if( dav_session.proxy_port > 0 ) {
|
if( ctx->dav_session.proxy_port > 0 ) {
|
||||||
port = dav_session.proxy_port;
|
port = ctx->dav_session.proxy_port;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( c_streq(dav_session.proxy_type, "NoProxy" )) {
|
if( c_streq(ctx->dav_session.proxy_type, "NoProxy" )) {
|
||||||
DEBUG_WEBDAV("No proxy configured.");
|
DEBUG_WEBDAV("No proxy configured.");
|
||||||
re = 0;
|
re = 0;
|
||||||
} else if( c_streq(dav_session.proxy_type, "DefaultProxy") ||
|
} else if( c_streq(ctx->dav_session.proxy_type, "DefaultProxy") ||
|
||||||
c_streq(dav_session.proxy_type, "HttpProxy") ||
|
c_streq(ctx->dav_session.proxy_type, "HttpProxy") ||
|
||||||
c_streq(dav_session.proxy_type, "HttpCachingProxy") ||
|
c_streq(ctx->dav_session.proxy_type, "HttpCachingProxy") ||
|
||||||
c_streq(dav_session.proxy_type, "Socks5Proxy")) {
|
c_streq(ctx->dav_session.proxy_type, "Socks5Proxy")) {
|
||||||
|
|
||||||
if( dav_session.proxy_host ) {
|
if( ctx->dav_session.proxy_host ) {
|
||||||
DEBUG_WEBDAV("%s at %s:%d", dav_session.proxy_type, dav_session.proxy_host, port );
|
DEBUG_WEBDAV("%s at %s:%d", ctx->dav_session.proxy_type, ctx->dav_session.proxy_host, port );
|
||||||
if (c_streq(dav_session.proxy_type, "Socks5Proxy")) {
|
if (c_streq(ctx->dav_session.proxy_type, "Socks5Proxy")) {
|
||||||
ne_session_socks_proxy(session, NE_SOCK_SOCKSV5, dav_session.proxy_host, port,
|
ne_session_socks_proxy(session, NE_SOCK_SOCKSV5, ctx->dav_session.proxy_host, port,
|
||||||
dav_session.proxy_user, dav_session.proxy_pwd);
|
ctx->dav_session.proxy_user, ctx->dav_session.proxy_pwd);
|
||||||
} else {
|
} else {
|
||||||
ne_session_proxy(session, dav_session.proxy_host, port );
|
ne_session_proxy(session, ctx->dav_session.proxy_host, port );
|
||||||
}
|
}
|
||||||
re = 2;
|
re = 2;
|
||||||
} else {
|
} else {
|
||||||
DEBUG_WEBDAV("%s requested but no proxy host defined.", dav_session.proxy_type );
|
DEBUG_WEBDAV("%s requested but no proxy host defined.", ctx->dav_session.proxy_type );
|
||||||
/* we used to try ne_system_session_proxy here, but we should rather err out
|
/* we used to try ne_system_session_proxy here, but we should rather err out
|
||||||
to behave exactly like the caller. */
|
to behave exactly like the caller. */
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DEBUG_WEBDAV( "Unsupported Proxy: %s", dav_session.proxy_type );
|
DEBUG_WEBDAV( "Unsupported Proxy: %s", ctx->dav_session.proxy_type );
|
||||||
}
|
}
|
||||||
|
|
||||||
return re;
|
return re;
|
||||||
|
@ -303,9 +232,9 @@ static void post_request_hook(ne_request *req, void *userdata, const ne_status *
|
||||||
const char *sc = NULL;
|
const char *sc = NULL;
|
||||||
char *key = NULL;
|
char *key = NULL;
|
||||||
|
|
||||||
(void) userdata;
|
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
|
||||||
|
|
||||||
if (dav_session.session_key)
|
if (ctx->dav_session.session_key)
|
||||||
return; /* We already have a session cookie, and we should ignore other ones */
|
return; /* We already have a session cookie, and we should ignore other ones */
|
||||||
|
|
||||||
if(!(status && req)) return;
|
if(!(status && req)) return;
|
||||||
|
@ -373,8 +302,8 @@ static void post_request_hook(ne_request *req, void *userdata, const ne_status *
|
||||||
}
|
}
|
||||||
if( key ) {
|
if( key ) {
|
||||||
DEBUG_WEBDAV("----> Session-key: %s", key);
|
DEBUG_WEBDAV("----> Session-key: %s", key);
|
||||||
SAFE_FREE(dav_session.session_key);
|
SAFE_FREE(ctx->dav_session.session_key);
|
||||||
dav_session.session_key = key;
|
ctx->dav_session.session_key = key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -385,13 +314,14 @@ static void post_request_hook(ne_request *req, void *userdata, const ne_status *
|
||||||
static void request_created_hook(ne_request *req, void *userdata,
|
static void request_created_hook(ne_request *req, void *userdata,
|
||||||
const char *method, const char *requri)
|
const char *method, const char *requri)
|
||||||
{
|
{
|
||||||
(void) userdata;
|
// FIXME Can possibly be merged with pre_send_hook
|
||||||
|
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t *) userdata;
|
||||||
(void) method;
|
(void) method;
|
||||||
(void) requri;
|
(void) requri;
|
||||||
|
|
||||||
if( !req ) return;
|
if( !req ) return;
|
||||||
|
|
||||||
if(dav_session.proxy_type) {
|
if(ctx->dav_session.proxy_type) {
|
||||||
/* required for NTLM */
|
/* required for NTLM */
|
||||||
ne_add_request_header(req, "Proxy-Connection", "Keep-Alive");
|
ne_add_request_header(req, "Proxy-Connection", "Keep-Alive");
|
||||||
}
|
}
|
||||||
|
@ -404,12 +334,12 @@ static void request_created_hook(ne_request *req, void *userdata,
|
||||||
static void pre_send_hook(ne_request *req, void *userdata,
|
static void pre_send_hook(ne_request *req, void *userdata,
|
||||||
ne_buffer *header)
|
ne_buffer *header)
|
||||||
{
|
{
|
||||||
(void) userdata;
|
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t *) userdata;
|
||||||
|
|
||||||
if( !req ) return;
|
if( !req ) return;
|
||||||
|
|
||||||
if(dav_session.session_key) {
|
if(ctx->dav_session.session_key) {
|
||||||
ne_buffer_concat(header, "Cookie: ", dav_session.session_key, "\r\n", NULL);
|
ne_buffer_concat(header, "Cookie: ", ctx->dav_session.session_key, "\r\n", NULL);
|
||||||
} else {
|
} else {
|
||||||
DEBUG_WEBDAV("csync pre_send_hook We don't have a Auth Cookie (session_key), this is wrong!");
|
DEBUG_WEBDAV("csync pre_send_hook We don't have a Auth Cookie (session_key), this is wrong!");
|
||||||
}
|
}
|
||||||
|
@ -419,16 +349,15 @@ static int post_send_hook(ne_request *req, void *userdata,
|
||||||
const ne_status *status)
|
const ne_status *status)
|
||||||
{
|
{
|
||||||
const char *location;
|
const char *location;
|
||||||
|
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t *) userdata;
|
||||||
(void) userdata;
|
|
||||||
(void) status;
|
(void) status;
|
||||||
|
|
||||||
location = ne_get_response_header(req, "Location");
|
location = ne_get_response_header(req, "Location");
|
||||||
|
|
||||||
if( !location ) return NE_OK;
|
if( !location ) return NE_OK;
|
||||||
|
|
||||||
if( dav_session.redir_callback ) {
|
if( ctx->dav_session.redir_callback ) {
|
||||||
if( dav_session.redir_callback( dav_session.csync_ctx, location ) ) {
|
if( ctx->dav_session.redir_callback( ctx->csync_ctx, location ) ) {
|
||||||
return NE_REDIRECT;
|
return NE_REDIRECT;
|
||||||
} else {
|
} else {
|
||||||
return NE_RETRY;
|
return NE_RETRY;
|
||||||
|
@ -438,37 +367,12 @@ static int post_send_hook(ne_request *req, void *userdata,
|
||||||
return NE_REDIRECT;
|
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
|
* Connect to a DAV server
|
||||||
* This function sets the flag _connected if the connection is established
|
* This function sets the flag _connected if the connection is established
|
||||||
* and returns if the flag is set, so calling it frequently is save.
|
* and returns if the flag is set, so calling it frequently is save.
|
||||||
*/
|
*/
|
||||||
static int dav_connect(const char *base_url) {
|
static int dav_connect(csync_owncloud_ctx_t *ctx, const char *base_url) {
|
||||||
int useSSL = 0;
|
int useSSL = 0;
|
||||||
int rc;
|
int rc;
|
||||||
char protocol[6] = {'\0'};
|
char protocol[6] = {'\0'};
|
||||||
|
@ -479,11 +383,14 @@ static int dav_connect(const char *base_url) {
|
||||||
unsigned int port = 0;
|
unsigned int port = 0;
|
||||||
int proxystate = -1;
|
int proxystate = -1;
|
||||||
|
|
||||||
if (_connected) {
|
if (ctx->_connected) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = c_parse_uri( base_url, &scheme, &dav_session.user, &dav_session.pwd, &host, &port, &path );
|
rc = c_parse_uri( base_url, &scheme,
|
||||||
|
&ctx->dav_session.user,
|
||||||
|
&ctx->dav_session.pwd,
|
||||||
|
&host, &port, &path );
|
||||||
if( rc < 0 ) {
|
if( rc < 0 ) {
|
||||||
DEBUG_WEBDAV("Failed to parse uri %s", base_url );
|
DEBUG_WEBDAV("Failed to parse uri %s", base_url );
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -505,29 +412,29 @@ static int dav_connect(const char *base_url) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_WEBDAV("* user %s", dav_session.user ? dav_session.user : "");
|
DEBUG_WEBDAV("* user %s", ctx->dav_session.user ? ctx->dav_session.user : "");
|
||||||
|
|
||||||
if (port == 0) {
|
if (port == 0) {
|
||||||
port = ne_uri_defaultport(protocol);
|
port = ne_uri_defaultport(protocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
dav_session.ctx = ne_session_create( protocol, host, port);
|
ctx->dav_session.ctx = ne_session_create( protocol, host, port);
|
||||||
|
|
||||||
if (dav_session.ctx == NULL) {
|
if (ctx->dav_session.ctx == NULL) {
|
||||||
DEBUG_WEBDAV("Session create with protocol %s failed", protocol );
|
DEBUG_WEBDAV("Session create with protocol %s failed", protocol );
|
||||||
rc = -1;
|
rc = -1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dav_session.read_timeout != 0) {
|
if (ctx->dav_session.read_timeout != 0) {
|
||||||
ne_set_read_timeout(dav_session.ctx, dav_session.read_timeout);
|
ne_set_read_timeout(ctx->dav_session.ctx, ctx->dav_session.read_timeout);
|
||||||
DEBUG_WEBDAV("Timeout set to %u seconds", dav_session.read_timeout );
|
DEBUG_WEBDAV("Timeout set to %u seconds", ctx->dav_session.read_timeout );
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf( uaBuf, sizeof(uaBuf), "Mozilla/5.0 (%s) csyncoC/%s",
|
snprintf( uaBuf, sizeof(uaBuf), "Mozilla/5.0 (%s) csyncoC/%s",
|
||||||
get_platform(), CSYNC_STRINGIFY( LIBCSYNC_VERSION ));
|
csync_owncloud_get_platform(), CSYNC_STRINGIFY( LIBCSYNC_VERSION ));
|
||||||
ne_set_useragent( dav_session.ctx, uaBuf);
|
ne_set_useragent( ctx->dav_session.ctx, uaBuf);
|
||||||
ne_set_server_auth(dav_session.ctx, ne_auth, 0 );
|
ne_set_server_auth(ctx->dav_session.ctx, authentication_callback_by_neon, ctx);
|
||||||
|
|
||||||
if( useSSL ) {
|
if( useSSL ) {
|
||||||
if (!ne_has_support(NE_FEATURE_SSL)) {
|
if (!ne_has_support(NE_FEATURE_SSL)) {
|
||||||
|
@ -536,28 +443,28 @@ static int dav_connect(const char *base_url) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ne_ssl_trust_default_ca( dav_session.ctx );
|
ne_ssl_trust_default_ca( ctx->dav_session.ctx );
|
||||||
ne_ssl_set_verify( dav_session.ctx, verify_sslcert, 0 );
|
ne_ssl_set_verify( ctx->dav_session.ctx, ssl_callback_by_neon, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hook called when a request is created. It sets the proxy connection header. */
|
/* Hook called when a request is created. It sets the proxy connection header. */
|
||||||
ne_hook_create_request( dav_session.ctx, request_created_hook, NULL );
|
ne_hook_create_request( ctx->dav_session.ctx, request_created_hook, ctx );
|
||||||
/* Hook called after response headers are read. It gets the Session ID. */
|
/* Hook called after response headers are read. It gets the Session ID. */
|
||||||
ne_hook_post_headers( dav_session.ctx, post_request_hook, NULL );
|
ne_hook_post_headers( ctx->dav_session.ctx, post_request_hook, ctx );
|
||||||
/* Hook called before a request is sent. It sets the cookies. */
|
/* Hook called before a request is sent. It sets the cookies. */
|
||||||
ne_hook_pre_send( dav_session.ctx, pre_send_hook, NULL );
|
ne_hook_pre_send( ctx->dav_session.ctx, pre_send_hook, ctx );
|
||||||
/* Hook called after request is dispatched. Used for handling possible redirections. */
|
/* Hook called after request is dispatched. Used for handling possible redirections. */
|
||||||
ne_hook_post_send( dav_session.ctx, post_send_hook, NULL );
|
ne_hook_post_send( ctx->dav_session.ctx, post_send_hook, ctx );
|
||||||
|
|
||||||
/* Proxy support */
|
/* Proxy support */
|
||||||
proxystate = configureProxy( dav_session.ctx );
|
proxystate = configureProxy( ctx, ctx->dav_session.ctx );
|
||||||
if( proxystate < 0 ) {
|
if( proxystate < 0 ) {
|
||||||
DEBUG_WEBDAV("Error: Proxy-Configuration failed.");
|
DEBUG_WEBDAV("Error: Proxy-Configuration failed.");
|
||||||
} else if( proxystate > 0 ) {
|
} else if( proxystate > 0 ) {
|
||||||
ne_set_proxy_auth( dav_session.ctx, ne_proxy_auth, 0 );
|
ne_set_proxy_auth( ctx->dav_session.ctx, proxy_authentication_callback_by_neon, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
_connected = 1;
|
ctx->_connected = 1;
|
||||||
rc = 0;
|
rc = 0;
|
||||||
out:
|
out:
|
||||||
SAFE_FREE(path);
|
SAFE_FREE(path);
|
||||||
|
@ -573,7 +480,7 @@ out:
|
||||||
* and fills a resource struct and stores it to the result list which
|
* and fills a resource struct and stores it to the result list which
|
||||||
* is stored in the listdir_context.
|
* is stored in the listdir_context.
|
||||||
*/
|
*/
|
||||||
static void results(void *userdata,
|
static void propfind_results_callback(void *userdata,
|
||||||
const ne_uri *uri,
|
const ne_uri *uri,
|
||||||
const ne_prop_result_set *set)
|
const ne_prop_result_set *set)
|
||||||
{
|
{
|
||||||
|
@ -583,6 +490,8 @@ static void results(void *userdata,
|
||||||
const char *resourcetype = NULL;
|
const char *resourcetype = NULL;
|
||||||
const char *md5sum = NULL;
|
const char *md5sum = NULL;
|
||||||
const char *file_id = NULL;
|
const char *file_id = NULL;
|
||||||
|
const char *directDownloadUrl = NULL;
|
||||||
|
const char *directDownloadCookies = NULL;
|
||||||
const ne_status *status = NULL;
|
const ne_status *status = NULL;
|
||||||
char *path = ne_path_unescape( uri->path );
|
char *path = ne_path_unescape( uri->path );
|
||||||
|
|
||||||
|
@ -608,6 +517,8 @@ static void results(void *userdata,
|
||||||
resourcetype = ne_propset_value( set, &ls_props[2] );
|
resourcetype = ne_propset_value( set, &ls_props[2] );
|
||||||
md5sum = ne_propset_value( set, &ls_props[3] );
|
md5sum = ne_propset_value( set, &ls_props[3] );
|
||||||
file_id = ne_propset_value( set, &ls_props[4] );
|
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] );
|
||||||
|
|
||||||
newres->type = resr_normal;
|
newres->type = resr_normal;
|
||||||
if( clength == NULL && resourcetype && strncmp( resourcetype, "<DAV:collection>", 16 ) == 0) {
|
if( clength == NULL && resourcetype && strncmp( resourcetype, "<DAV:collection>", 16 ) == 0) {
|
||||||
|
@ -631,6 +542,13 @@ static void results(void *userdata,
|
||||||
|
|
||||||
csync_vio_set_file_id(newres->file_id, file_id);
|
csync_vio_set_file_id(newres->file_id, file_id);
|
||||||
|
|
||||||
|
if (directDownloadUrl) {
|
||||||
|
newres->directDownloadUrl = c_strdup(directDownloadUrl);
|
||||||
|
}
|
||||||
|
if (directDownloadCookies) {
|
||||||
|
newres->directDownloadCookies = c_strdup(directDownloadCookies);
|
||||||
|
}
|
||||||
|
|
||||||
/* prepend the new resource to the result list */
|
/* prepend the new resource to the result list */
|
||||||
newres->next = fetchCtx->list;
|
newres->next = fetchCtx->list;
|
||||||
fetchCtx->list = newres;
|
fetchCtx->list = newres;
|
||||||
|
@ -643,7 +561,7 @@ static void results(void *userdata,
|
||||||
/*
|
/*
|
||||||
* fetches a resource list from the WebDAV server. This is equivalent to list dir.
|
* fetches a resource list from the WebDAV server. This is equivalent to list dir.
|
||||||
*/
|
*/
|
||||||
static struct listdir_context *fetch_resource_list(const char *uri, int depth)
|
static struct listdir_context *fetch_resource_list(csync_owncloud_ctx_t *ctx, const char *uri, int depth)
|
||||||
{
|
{
|
||||||
struct listdir_context *fetchCtx;
|
struct listdir_context *fetchCtx;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -657,12 +575,12 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
|
||||||
|
|
||||||
/* The old legacy one-level PROPFIND cache. Also gets filled
|
/* The old legacy one-level PROPFIND cache. Also gets filled
|
||||||
by the recursive cache if 'infinity' did not suceed. */
|
by the recursive cache if 'infinity' did not suceed. */
|
||||||
if (propfind_cache) {
|
if (ctx->propfind_cache) {
|
||||||
if (c_streq(curi, propfind_cache->target)) {
|
if (c_streq(curi, ctx->propfind_cache->target)) {
|
||||||
DEBUG_WEBDAV("fetch_resource_list Using simple PROPFIND cache %s", curi);
|
DEBUG_WEBDAV("fetch_resource_list Using simple PROPFIND cache %s", curi);
|
||||||
propfind_cache->ref++;
|
ctx->propfind_cache->ref++;
|
||||||
SAFE_FREE(curi);
|
SAFE_FREE(curi);
|
||||||
return propfind_cache;
|
return ctx->propfind_cache;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -678,10 +596,10 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
|
||||||
fetchCtx->ref = 1;
|
fetchCtx->ref = 1;
|
||||||
|
|
||||||
/* do a propfind request and parse the results in the results function, set as callback */
|
/* do a propfind request and parse the results in the results function, set as callback */
|
||||||
hdl = ne_propfind_create(dav_session.ctx, curi, depth);
|
hdl = ne_propfind_create(ctx->dav_session.ctx, curi, depth);
|
||||||
|
|
||||||
if(hdl) {
|
if(hdl) {
|
||||||
ret = ne_propfind_named(hdl, ls_props, results, fetchCtx);
|
ret = ne_propfind_named(hdl, ls_props, propfind_results_callback, fetchCtx);
|
||||||
request = ne_propfind_get_request( hdl );
|
request = ne_propfind_get_request( hdl );
|
||||||
req_status = ne_get_status( request );
|
req_status = ne_get_status( request );
|
||||||
}
|
}
|
||||||
|
@ -694,14 +612,14 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
|
||||||
DEBUG_WEBDAV("ERROR: Request failed: status %d (%s)", req_status->code,
|
DEBUG_WEBDAV("ERROR: Request failed: status %d (%s)", req_status->code,
|
||||||
req_status->reason_phrase);
|
req_status->reason_phrase);
|
||||||
ret = NE_CONNECT;
|
ret = NE_CONNECT;
|
||||||
set_error_message(req_status->reason_phrase);
|
set_error_message(ctx, req_status->reason_phrase);
|
||||||
}
|
}
|
||||||
DEBUG_WEBDAV("Simple propfind result code %d.", req_status->code);
|
DEBUG_WEBDAV("Simple propfind result code %d.", req_status->code);
|
||||||
} else {
|
} else {
|
||||||
if( ret == NE_ERROR && req_status->code == 404) {
|
if( ret == NE_ERROR && req_status->code == 404) {
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
} else {
|
} else {
|
||||||
set_errno_from_neon_errcode(ret);
|
set_errno_from_neon_errcode(ctx, ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -716,18 +634,18 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
|
||||||
DEBUG_WEBDAV("ERROR: Content type of propfind request not XML: %s.",
|
DEBUG_WEBDAV("ERROR: Content type of propfind request not XML: %s.",
|
||||||
content_type ? content_type: "<empty>");
|
content_type ? content_type: "<empty>");
|
||||||
errno = ERRNO_WRONG_CONTENT;
|
errno = ERRNO_WRONG_CONTENT;
|
||||||
set_error_message("Server error: PROPFIND reply is not XML formatted!");
|
set_error_message(ctx, "Server error: PROPFIND reply is not XML formatted!");
|
||||||
ret = NE_CONNECT;
|
ret = NE_CONNECT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ret != NE_OK ) {
|
if( ret != NE_OK ) {
|
||||||
const char *err = NULL;
|
const char *err = NULL;
|
||||||
set_errno_from_neon_errcode(ret);
|
set_errno_from_neon_errcode(ctx, ret);
|
||||||
|
|
||||||
err = ne_get_error( dav_session.ctx );
|
err = ne_get_error( ctx->dav_session.ctx );
|
||||||
if(err) {
|
if(err) {
|
||||||
set_error_message(err);
|
set_error_message(ctx, err);
|
||||||
}
|
}
|
||||||
DEBUG_WEBDAV("WRN: propfind named failed with %d, request error: %s", ret, err ? err : "<nil>");
|
DEBUG_WEBDAV("WRN: propfind named failed with %d, request error: %s", ret, err ? err : "<nil>");
|
||||||
}
|
}
|
||||||
|
@ -740,19 +658,19 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
free_fetchCtx(propfind_cache);
|
free_fetchCtx(ctx->propfind_cache);
|
||||||
propfind_cache = fetchCtx;
|
ctx->propfind_cache = fetchCtx;
|
||||||
propfind_cache->ref++;
|
ctx->propfind_cache->ref++;
|
||||||
return fetchCtx;
|
return fetchCtx;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct listdir_context *fetch_resource_list_attempts(const char *uri, int depth)
|
static struct listdir_context *fetch_resource_list_attempts(csync_owncloud_ctx_t *ctx, const char *uri, int depth)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
struct listdir_context *fetchCtx = NULL;
|
struct listdir_context *fetchCtx = NULL;
|
||||||
for(i = 0; i < 10; ++i) {
|
for(i = 0; i < 10; ++i) {
|
||||||
fetchCtx = fetch_resource_list(uri, depth);
|
fetchCtx = fetch_resource_list(ctx, uri, depth);
|
||||||
if(fetchCtx) break;
|
if(fetchCtx) break;
|
||||||
/* only loop in case the content is not XML formatted. Otherwise for every
|
/* only loop in case the content is not XML formatted. Otherwise for every
|
||||||
* non successful stat (for non existing directories) its tried 10 times. */
|
* non successful stat (for non existing directories) its tried 10 times. */
|
||||||
|
@ -764,165 +682,39 @@ static struct listdir_context *fetch_resource_list_attempts(const char *uri, int
|
||||||
return fetchCtx;
|
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
|
* directory functions
|
||||||
*/
|
*/
|
||||||
csync_vio_handle_t *owncloud_opendir(const char *uri) {
|
csync_vio_handle_t *owncloud_opendir(CSYNC *ctx, const char *uri) {
|
||||||
struct listdir_context *fetchCtx = NULL;
|
struct listdir_context *fetchCtx = NULL;
|
||||||
char *curi = NULL;
|
char *curi = NULL;
|
||||||
|
|
||||||
DEBUG_WEBDAV("opendir method called on %s", uri );
|
DEBUG_WEBDAV("opendir method called on %s", uri );
|
||||||
|
|
||||||
if (dav_connect( uri ) < 0) {
|
if (dav_connect( ctx->owncloud_context, uri ) < 0) {
|
||||||
DEBUG_WEBDAV("connection failed");
|
DEBUG_WEBDAV("connection failed");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
curi = _cleanPath( uri );
|
curi = _cleanPath( uri );
|
||||||
if (is_first_propfind && !dav_session.no_recursive_propfind) {
|
if (ctx->owncloud_context->is_first_propfind && !ctx->owncloud_context->dav_session.no_recursive_propfind) {
|
||||||
is_first_propfind = false;
|
ctx->owncloud_context->is_first_propfind = false;
|
||||||
// Try to fill it
|
// Try to fill it
|
||||||
fill_recursive_propfind_cache(uri, curi);
|
fill_recursive_propfind_cache(ctx->owncloud_context, uri, curi);
|
||||||
}
|
}
|
||||||
if (propfind_recursive_cache) {
|
if (ctx->owncloud_context->propfind_recursive_cache) {
|
||||||
// Try to fetch from recursive cache (if we have one)
|
// Try to fetch from recursive cache (if we have one)
|
||||||
fetchCtx = get_listdir_context_from_recursive_cache(curi);
|
fetchCtx = get_listdir_context_from_recursive_cache(ctx->owncloud_context, curi);
|
||||||
}
|
}
|
||||||
SAFE_FREE(curi);
|
SAFE_FREE(curi);
|
||||||
is_first_propfind = false;
|
ctx->owncloud_context->is_first_propfind = false;
|
||||||
if (fetchCtx) {
|
if (fetchCtx) {
|
||||||
return fetchCtx;
|
return fetchCtx;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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);
|
fetchCtx = fetch_resource_list_attempts( ctx->owncloud_context, uri, NE_DEPTH_ONE);
|
||||||
if( !fetchCtx ) {
|
if( !fetchCtx ) {
|
||||||
/* errno is set properly in fetch_resource_list */
|
/* errno is set properly in fetch_resource_list */
|
||||||
DEBUG_WEBDAV("Errno set to %d", errno);
|
DEBUG_WEBDAV("Errno set to %d", errno);
|
||||||
|
@ -935,7 +727,8 @@ csync_vio_handle_t *owncloud_opendir(const char *uri) {
|
||||||
/* no freeing of curi because its part of the fetchCtx and gets freed later */
|
/* no freeing of curi because its part of the fetchCtx and gets freed later */
|
||||||
}
|
}
|
||||||
|
|
||||||
int owncloud_closedir(csync_vio_handle_t *dhandle) {
|
int owncloud_closedir(CSYNC *ctx, csync_vio_handle_t *dhandle) {
|
||||||
|
(void)ctx;
|
||||||
|
|
||||||
struct listdir_context *fetchCtx = dhandle;
|
struct listdir_context *fetchCtx = dhandle;
|
||||||
|
|
||||||
|
@ -944,7 +737,8 @@ int owncloud_closedir(csync_vio_handle_t *dhandle) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
csync_vio_file_stat_t *owncloud_readdir(csync_vio_handle_t *dhandle) {
|
csync_vio_file_stat_t *owncloud_readdir(CSYNC *ctx, csync_vio_handle_t *dhandle) {
|
||||||
|
(void)ctx;
|
||||||
struct listdir_context *fetchCtx = dhandle;
|
struct listdir_context *fetchCtx = dhandle;
|
||||||
|
|
||||||
// DEBUG_WEBDAV("owncloud_readdir" );
|
// DEBUG_WEBDAV("owncloud_readdir" );
|
||||||
|
@ -971,8 +765,10 @@ csync_vio_file_stat_t *owncloud_readdir(csync_vio_handle_t *dhandle) {
|
||||||
*/
|
*/
|
||||||
escaped_path = ne_path_escape( currResource->uri );
|
escaped_path = ne_path_escape( currResource->uri );
|
||||||
if (ne_path_compare(fetchCtx->target, escaped_path) != 0) {
|
if (ne_path_compare(fetchCtx->target, escaped_path) != 0) {
|
||||||
csync_vio_file_stat_t* lfs = resourceToFileStat(currResource);
|
// Convert the resource for the caller
|
||||||
fill_stat_cache(lfs);
|
csync_vio_file_stat_t* lfs = csync_vio_file_stat_new();
|
||||||
|
resourceToFileStat(lfs, currResource);
|
||||||
|
|
||||||
SAFE_FREE( escaped_path );
|
SAFE_FREE( escaped_path );
|
||||||
return lfs;
|
return lfs;
|
||||||
}
|
}
|
||||||
|
@ -984,39 +780,51 @@ csync_vio_file_stat_t *owncloud_readdir(csync_vio_handle_t *dhandle) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *owncloud_error_string(void)
|
char *owncloud_error_string(CSYNC* ctx)
|
||||||
{
|
{
|
||||||
return dav_session.error_string;
|
return ctx->owncloud_context->dav_session.error_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
int owncloud_commit(void) {
|
int owncloud_commit(CSYNC* ctx) {
|
||||||
|
clear_propfind_recursive_cache(ctx->owncloud_context);
|
||||||
|
|
||||||
clean_caches();
|
free_fetchCtx(ctx->owncloud_context->propfind_cache);
|
||||||
|
ctx->owncloud_context->propfind_cache = NULL;
|
||||||
|
|
||||||
if( dav_session.ctx ) {
|
if( ctx->owncloud_context->dav_session.ctx ) {
|
||||||
ne_forget_auth(dav_session.ctx);
|
ne_forget_auth(ctx->owncloud_context->dav_session.ctx);
|
||||||
ne_session_destroy( 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;
|
||||||
/* DEBUG_WEBDAV( "********** vio_module_shutdown" ); */
|
/* DEBUG_WEBDAV( "********** vio_module_shutdown" ); */
|
||||||
|
|
||||||
dav_session.ctx = 0;
|
ctx->owncloud_context->dav_session.ctx = 0;
|
||||||
|
|
||||||
// ne_sock_exit();
|
// ne_sock_exit();
|
||||||
_connected = 0; /* triggers dav_connect to go through the whole neon setup */
|
ctx->owncloud_context->_connected = 0; /* triggers dav_connect to go through the whole neon setup */
|
||||||
|
|
||||||
SAFE_FREE( dav_session.user );
|
SAFE_FREE( ctx->owncloud_context->dav_session.user );
|
||||||
SAFE_FREE( dav_session.pwd );
|
SAFE_FREE( ctx->owncloud_context->dav_session.pwd );
|
||||||
SAFE_FREE( dav_session.session_key);
|
SAFE_FREE( ctx->owncloud_context->dav_session.session_key);
|
||||||
SAFE_FREE( dav_session.error_string );
|
SAFE_FREE( ctx->owncloud_context->dav_session.error_string );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int owncloud_set_property(const char *key, void *data) {
|
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) {
|
||||||
#define READ_STRING_PROPERTY(P) \
|
#define READ_STRING_PROPERTY(P) \
|
||||||
if (c_streq(key, #P)) { \
|
if (c_streq(key, #P)) { \
|
||||||
SAFE_FREE(dav_session.P); \
|
SAFE_FREE(ctx->owncloud_context->dav_session.P); \
|
||||||
dav_session.P = c_strdup((const char*)data); \
|
ctx->owncloud_context->dav_session.P = c_strdup((const char*)data); \
|
||||||
return 0; \
|
return 0; \
|
||||||
}
|
}
|
||||||
READ_STRING_PROPERTY(session_key)
|
READ_STRING_PROPERTY(session_key)
|
||||||
|
@ -1027,48 +835,43 @@ int owncloud_set_property(const char *key, void *data) {
|
||||||
#undef READ_STRING_PROPERTY
|
#undef READ_STRING_PROPERTY
|
||||||
|
|
||||||
if (c_streq(key, "proxy_port")) {
|
if (c_streq(key, "proxy_port")) {
|
||||||
dav_session.proxy_port = *(int*)(data);
|
ctx->owncloud_context->dav_session.proxy_port = *(int*)(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (c_streq(key, "read_timeout") || c_streq(key, "timeout")) {
|
if (c_streq(key, "read_timeout") || c_streq(key, "timeout")) {
|
||||||
dav_session.read_timeout = *(int*)(data);
|
ctx->owncloud_context->dav_session.read_timeout = *(int*)(data);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if( c_streq(key, "csync_context")) {
|
|
||||||
dav_session.csync_ctx = data;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if( c_streq(key, "get_dav_session")) {
|
if( c_streq(key, "get_dav_session")) {
|
||||||
/* Give the ne_session to the caller */
|
/* Give the ne_session to the caller */
|
||||||
*(ne_session**)data = dav_session.ctx;
|
*(ne_session**)data = ctx->owncloud_context->dav_session.ctx;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if( c_streq(key, "no_recursive_propfind")) {
|
if( c_streq(key, "no_recursive_propfind")) {
|
||||||
dav_session.no_recursive_propfind = *(bool*)(data);
|
ctx->owncloud_context->dav_session.no_recursive_propfind = *(bool*)(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if( c_streq(key, "redirect_callback")) {
|
if( c_streq(key, "redirect_callback")) {
|
||||||
if (data) {
|
if (data) {
|
||||||
csync_owncloud_redirect_callback_t* cb_wrapper = data;
|
csync_owncloud_redirect_callback_t* cb_wrapper = data;
|
||||||
|
|
||||||
dav_session.redir_callback = *cb_wrapper;
|
ctx->owncloud_context->dav_session.redir_callback = *cb_wrapper;
|
||||||
} else {
|
} else {
|
||||||
dav_session.redir_callback = NULL;
|
ctx->owncloud_context->dav_session.redir_callback = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void owncloud_init(void *userdata) {
|
void owncloud_init(CSYNC* ctx) {
|
||||||
|
|
||||||
_userdata = userdata;
|
ctx->owncloud_context = c_malloc( sizeof( struct csync_owncloud_ctx_s ));
|
||||||
_connected = 0; /* triggers dav_connect to go through the whole neon setup */
|
ctx->owncloud_context->csync_ctx = ctx; // back reference
|
||||||
|
ctx->owncloud_context->is_first_propfind = true;
|
||||||
memset(&dav_session, 0, sizeof(dav_session));
|
|
||||||
|
|
||||||
/* Disable it, Mirall can enable it for the first sync (= no DB)*/
|
/* Disable it, Mirall can enable it for the first sync (= no DB)*/
|
||||||
dav_session.no_recursive_propfind = true;
|
ctx->owncloud_context->dav_session.no_recursive_propfind = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* vim: set ts=4 sw=4 et cindent: */
|
/* vim: set ts=4 sw=4 et cindent: */
|
||||||
|
|
|
@ -21,159 +21,18 @@
|
||||||
#ifndef CSYNC_OWNCLOUD_H
|
#ifndef CSYNC_OWNCLOUD_H
|
||||||
#define 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.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_file_stat.h"
|
||||||
#include "vio/csync_vio.h"
|
#include "vio/csync_vio.h"
|
||||||
|
|
||||||
#include "csync_log.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);
|
||||||
#define DEBUG_WEBDAV(...) csync_log( 9, "oc_module", __VA_ARGS__);
|
int owncloud_closedir(CSYNC* ctx, csync_vio_handle_t *dhandle);
|
||||||
|
int owncloud_commit(CSYNC* ctx);
|
||||||
enum resource_type {
|
void owncloud_destroy(CSYNC* ctx);
|
||||||
resr_normal = 0,
|
char *owncloud_error_string(CSYNC* ctx);
|
||||||
resr_collection,
|
void owncloud_init(CSYNC* ctx);
|
||||||
resr_reference,
|
int owncloud_set_property(CSYNC* ctx, const char *key, void *data);
|
||||||
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 */
|
#endif /* CSYNC_OWNCLOUD_H */
|
||||||
|
|
197
csync/src/csync_owncloud_private.h
Normal file
197
csync/src/csync_owncloud_private.h
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
/*
|
||||||
|
* 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"},
|
||||||
|
{ 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;
|
||||||
|
|
||||||
|
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 );
|
||||||
|
|
||||||
|
int _stat_perms( int type );
|
||||||
|
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
|
|
@ -20,42 +20,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "csync_owncloud.h"
|
#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) {
|
static void _tree_destructor(void *data) {
|
||||||
propfind_recursive_element_t *element = data;
|
propfind_recursive_element_t *element = data;
|
||||||
|
@ -64,27 +29,27 @@ static void _tree_destructor(void *data) {
|
||||||
SAFE_FREE(element);
|
SAFE_FREE(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear_propfind_recursive_cache(void)
|
void clear_propfind_recursive_cache(csync_owncloud_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
if (propfind_recursive_cache) {
|
if (ctx->propfind_recursive_cache) {
|
||||||
DEBUG_WEBDAV("clear_propfind_recursive_cache Invalidating..");
|
DEBUG_WEBDAV("clear_propfind_recursive_cache Invalidating..");
|
||||||
c_rbtree_destroy(propfind_recursive_cache, _tree_destructor);
|
c_rbtree_destroy(ctx->propfind_recursive_cache, _tree_destructor);
|
||||||
propfind_recursive_cache = NULL;
|
ctx->propfind_recursive_cache = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct listdir_context *get_listdir_context_from_recursive_cache(const char *curi)
|
struct listdir_context *get_listdir_context_from_recursive_cache(csync_owncloud_ctx_t *ctx, const char *curi)
|
||||||
{
|
{
|
||||||
propfind_recursive_element_t *element = NULL;
|
propfind_recursive_element_t *element = NULL;
|
||||||
struct listdir_context *fetchCtx = NULL;
|
struct listdir_context *fetchCtx = NULL;
|
||||||
struct resource *iterator, *r;
|
struct resource *iterator, *r;
|
||||||
|
|
||||||
if (!propfind_recursive_cache) {
|
if (!ctx->propfind_recursive_cache) {
|
||||||
DEBUG_WEBDAV("get_listdir_context_from_recursive_cache No cache");
|
DEBUG_WEBDAV("get_listdir_context_from_recursive_cache No cache");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
element = c_rbtree_node_data(c_rbtree_find(propfind_recursive_cache, curi));
|
element = c_rbtree_node_data(c_rbtree_find(ctx->propfind_recursive_cache, curi));
|
||||||
if (!element) {
|
if (!element) {
|
||||||
DEBUG_WEBDAV("get_listdir_context_from_recursive_cache No element %s in cache found", curi);
|
DEBUG_WEBDAV("get_listdir_context_from_recursive_cache No element %s in cache found", curi);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -128,27 +93,29 @@ static int _data_cmp(const void *a, const void *b) {
|
||||||
const propfind_recursive_element_t *elementB = b;
|
const propfind_recursive_element_t *elementB = b;
|
||||||
return ne_path_compare(elementA->self->uri, elementB->self->uri);
|
return ne_path_compare(elementA->self->uri, elementB->self->uri);
|
||||||
}
|
}
|
||||||
static void propfind_results_recursive(void *userdata,
|
static void propfind_results_recursive_callback(void *userdata,
|
||||||
const ne_uri *uri,
|
const ne_uri *uri,
|
||||||
const ne_prop_result_set *set)
|
const ne_prop_result_set *set)
|
||||||
{
|
{
|
||||||
struct resource *newres = 0;
|
struct resource *newres = 0;
|
||||||
const char *clength, *modtime, *file_id = NULL;
|
const char *clength, *modtime, *file_id = NULL;
|
||||||
|
const char *directDownloadUrl = NULL;
|
||||||
|
const char *directDownloadCookies = NULL;
|
||||||
const char *resourcetype = NULL;
|
const char *resourcetype = NULL;
|
||||||
const char *md5sum = NULL;
|
const char *md5sum = NULL;
|
||||||
const ne_status *status = NULL;
|
const ne_status *status = NULL;
|
||||||
char *path = ne_path_unescape( uri->path );
|
char *path = ne_path_unescape( uri->path );
|
||||||
char *parentPath;
|
char *parentPath;
|
||||||
char *propfindRootUri = (char*) userdata;
|
|
||||||
propfind_recursive_element_t *element = NULL;
|
propfind_recursive_element_t *element = NULL;
|
||||||
propfind_recursive_element_t *pElement = NULL;
|
propfind_recursive_element_t *pElement = NULL;
|
||||||
int depth = 0;
|
int depth = 0;
|
||||||
|
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
|
||||||
|
|
||||||
|
|
||||||
(void) status;
|
(void) status;
|
||||||
(void) propfindRootUri;
|
|
||||||
|
|
||||||
if (!propfind_recursive_cache) {
|
if (!ctx->propfind_recursive_cache) {
|
||||||
c_rbtree_create(&propfind_recursive_cache, _key_cmp, _data_cmp);
|
c_rbtree_create(&ctx->propfind_recursive_cache, _key_cmp, _data_cmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill the resource structure with the data about the file */
|
/* Fill the resource structure with the data about the file */
|
||||||
|
@ -163,14 +130,16 @@ static void propfind_results_recursive(void *userdata,
|
||||||
resourcetype = ne_propset_value( set, &ls_props[2] );
|
resourcetype = ne_propset_value( set, &ls_props[2] );
|
||||||
md5sum = ne_propset_value( set, &ls_props[3] );
|
md5sum = ne_propset_value( set, &ls_props[3] );
|
||||||
file_id = ne_propset_value( set, &ls_props[4] );
|
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] );
|
||||||
|
|
||||||
newres->type = resr_normal;
|
newres->type = resr_normal;
|
||||||
if( resourcetype && strncmp( resourcetype, "<DAV:collection>", 16 ) == 0) {
|
if( resourcetype && strncmp( resourcetype, "<DAV:collection>", 16 ) == 0) {
|
||||||
newres->type = resr_collection;
|
newres->type = resr_collection;
|
||||||
propfind_recursive_cache_folder_count++;
|
ctx->propfind_recursive_cache_folder_count++;
|
||||||
} else {
|
} else {
|
||||||
/* DEBUG_WEBDAV("propfind_results_recursive %s [%d]", newres->uri, newres->type); */
|
/* DEBUG_WEBDAV("propfind_results_recursive %s [%d]", newres->uri, newres->type); */
|
||||||
propfind_recursive_cache_file_count++;
|
ctx->propfind_recursive_cache_file_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modtime) {
|
if (modtime) {
|
||||||
|
@ -193,18 +162,26 @@ static void propfind_results_recursive(void *userdata,
|
||||||
DEBUG_WEBDAV("propfind_results_recursive %s [%s] %s", newres->uri, newres->type == resr_collection ? "collection" : "file", newres->md5);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
/* Create new item in rb tree */
|
/* Create new item in rb tree */
|
||||||
if (newres->type == resr_collection) {
|
if (newres->type == resr_collection) {
|
||||||
DEBUG_WEBDAV("propfind_results_recursive %s is a folder", newres->uri);
|
DEBUG_WEBDAV("propfind_results_recursive %s is a folder", newres->uri);
|
||||||
/* Check if in rb tree */
|
/* Check if in rb tree */
|
||||||
element = c_rbtree_node_data(c_rbtree_find(propfind_recursive_cache,uri->path));
|
element = c_rbtree_node_data(c_rbtree_find(ctx->propfind_recursive_cache,uri->path));
|
||||||
/* If not, create a new item and insert it */
|
/* If not, create a new item and insert it */
|
||||||
if (!element) {
|
if (!element) {
|
||||||
element = c_malloc(sizeof(propfind_recursive_element_t));
|
element = c_malloc(sizeof(propfind_recursive_element_t));
|
||||||
element->self = resource_dup(newres);
|
element->self = resource_dup(newres);
|
||||||
|
element->self->next = 0;
|
||||||
element->children = NULL;
|
element->children = NULL;
|
||||||
element->parent = NULL;
|
element->parent = NULL;
|
||||||
c_rbtree_insert(propfind_recursive_cache, element);
|
c_rbtree_insert(ctx->propfind_recursive_cache, element);
|
||||||
/* DEBUG_WEBDAV("results_recursive Added collection %s", newres->uri); */
|
/* DEBUG_WEBDAV("results_recursive Added collection %s", newres->uri); */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,7 +191,7 @@ static void propfind_results_recursive(void *userdata,
|
||||||
if (parentPath) {
|
if (parentPath) {
|
||||||
propfind_recursive_element_t *parentElement = NULL;
|
propfind_recursive_element_t *parentElement = NULL;
|
||||||
|
|
||||||
parentElement = c_rbtree_node_data(c_rbtree_find(propfind_recursive_cache,parentPath));
|
parentElement = c_rbtree_node_data(c_rbtree_find(ctx->propfind_recursive_cache,parentPath));
|
||||||
free(parentPath);
|
free(parentPath);
|
||||||
|
|
||||||
if (parentElement) {
|
if (parentElement) {
|
||||||
|
@ -230,9 +207,9 @@ static void propfind_results_recursive(void *userdata,
|
||||||
depth++;
|
depth++;
|
||||||
pElement = pElement->parent;
|
pElement = pElement->parent;
|
||||||
}
|
}
|
||||||
if (depth > propfind_recursive_cache_depth) {
|
if (depth > ctx->propfind_recursive_cache_depth) {
|
||||||
DEBUG_WEBDAV("propfind_results_recursive %s new maximum tree depth %d", newres->uri, depth);
|
DEBUG_WEBDAV("propfind_results_recursive %s new maximum tree depth %d", newres->uri, depth);
|
||||||
propfind_recursive_cache_depth = depth;
|
ctx->propfind_recursive_cache_depth = depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* DEBUG_WEBDAV("results_recursive Added child %s to collection %s", newres->uri, element->self->uri); */
|
/* DEBUG_WEBDAV("results_recursive Added child %s to collection %s", newres->uri, element->self->uri); */
|
||||||
|
@ -245,7 +222,7 @@ static void propfind_results_recursive(void *userdata,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void fetch_resource_list_recursive(const char *uri, const char *curi)
|
void fetch_resource_list_recursive(csync_owncloud_ctx_t *ctx, const char *uri, const char *curi)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
ne_propfind_handler *hdl = NULL;
|
ne_propfind_handler *hdl = NULL;
|
||||||
|
@ -257,10 +234,10 @@ void fetch_resource_list_recursive(const char *uri, const char *curi)
|
||||||
DEBUG_WEBDAV("fetch_resource_list_recursive Starting recursive propfind %s %s", uri, curi);
|
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 */
|
/* do a propfind request and parse the results in the results function, set as callback */
|
||||||
hdl = ne_propfind_create(dav_session.ctx, curi, depth);
|
hdl = ne_propfind_create(ctx->dav_session.ctx, curi, depth);
|
||||||
|
|
||||||
if(hdl) {
|
if(hdl) {
|
||||||
ret = ne_propfind_named(hdl, ls_props, propfind_results_recursive, (void*)curi);
|
ret = ne_propfind_named(hdl, ls_props, propfind_results_recursive_callback, ctx);
|
||||||
request = ne_propfind_get_request( hdl );
|
request = ne_propfind_get_request( hdl );
|
||||||
req_status = ne_get_status( request );
|
req_status = ne_get_status( request );
|
||||||
}
|
}
|
||||||
|
@ -272,14 +249,14 @@ void fetch_resource_list_recursive(const char *uri, const char *curi)
|
||||||
DEBUG_WEBDAV("ERROR: Request failed: status %d (%s)", req_status->code,
|
DEBUG_WEBDAV("ERROR: Request failed: status %d (%s)", req_status->code,
|
||||||
req_status->reason_phrase);
|
req_status->reason_phrase);
|
||||||
ret = NE_CONNECT;
|
ret = NE_CONNECT;
|
||||||
set_error_message(req_status->reason_phrase);
|
set_error_message(ctx, req_status->reason_phrase);
|
||||||
}
|
}
|
||||||
DEBUG_WEBDAV("Recursive propfind result code %d.", req_status ? req_status->code : 0);
|
DEBUG_WEBDAV("Recursive propfind result code %d.", req_status ? req_status->code : 0);
|
||||||
} else {
|
} else {
|
||||||
if( ret == NE_ERROR && req_status->code == 404) {
|
if( ret == NE_ERROR && req_status->code == 404) {
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
} else {
|
} else {
|
||||||
set_errno_from_neon_errcode(ret);
|
set_errno_from_neon_errcode(ctx, ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,7 +271,7 @@ void fetch_resource_list_recursive(const char *uri, const char *curi)
|
||||||
DEBUG_WEBDAV("ERROR: Content type of propfind request not XML: %s.",
|
DEBUG_WEBDAV("ERROR: Content type of propfind request not XML: %s.",
|
||||||
content_type ? content_type: "<empty>");
|
content_type ? content_type: "<empty>");
|
||||||
errno = ERRNO_WRONG_CONTENT;
|
errno = ERRNO_WRONG_CONTENT;
|
||||||
set_error_message("Server error: PROPFIND reply is not XML formatted!");
|
set_error_message(ctx, "Server error: PROPFIND reply is not XML formatted!");
|
||||||
ret = NE_CONNECT;
|
ret = NE_CONNECT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -302,7 +279,7 @@ void fetch_resource_list_recursive(const char *uri, const char *curi)
|
||||||
if( ret != NE_OK ) {
|
if( ret != NE_OK ) {
|
||||||
const char *err = NULL;
|
const char *err = NULL;
|
||||||
|
|
||||||
err = ne_get_error( dav_session.ctx );
|
err = ne_get_error( ctx->dav_session.ctx );
|
||||||
DEBUG_WEBDAV("WRN: propfind named failed with %d, request error: %s", ret, err ? err : "<nil>");
|
DEBUG_WEBDAV("WRN: propfind named failed with %d, request error: %s", ret, err ? err : "<nil>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,22 +294,21 @@ void fetch_resource_list_recursive(const char *uri, const char *curi)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called by owncloud_opendir()->fetch_resource_list() to fill the cache */
|
/* Called by owncloud_opendir()->fetch_resource_list() to fill the cache */
|
||||||
extern struct listdir_context *propfind_cache;
|
void fill_recursive_propfind_cache(csync_owncloud_ctx_t *ctx, const char *uri, const char *curi) {
|
||||||
void fill_recursive_propfind_cache(const char *uri, const char *curi) {
|
fetch_resource_list_recursive(ctx, uri, curi);
|
||||||
fetch_resource_list_recursive(uri, curi);
|
|
||||||
|
|
||||||
if (propfind_recursive_cache_depth <= 2) {
|
if (ctx->propfind_recursive_cache_depth <= 2) {
|
||||||
DEBUG_WEBDAV("fill_recursive_propfind_cache %s Server maybe did not give us an 'infinity' depth result", curi);
|
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 */
|
/* transform the cache to the normal cache in propfind_cache */
|
||||||
propfind_cache = get_listdir_context_from_recursive_cache(curi);
|
ctx->propfind_cache = get_listdir_context_from_recursive_cache(ctx, curi);
|
||||||
/* clear the cache, it is bogus since the server returned only results for Depth 1 */
|
/* clear the cache, it is bogus since the server returned only results for Depth 1 */
|
||||||
clear_propfind_recursive_cache();
|
clear_propfind_recursive_cache(ctx);
|
||||||
} else {
|
} else {
|
||||||
DEBUG_WEBDAV("fill_recursive_propfind_cache %s We received %d elements deep for 'infinity' depth (%d folders, %d files)",
|
DEBUG_WEBDAV("fill_recursive_propfind_cache %s We received %d elements deep for 'infinity' depth (%d folders, %d files)",
|
||||||
curi,
|
curi,
|
||||||
propfind_recursive_cache_depth,
|
ctx->propfind_recursive_cache_depth,
|
||||||
propfind_recursive_cache_folder_count,
|
ctx->propfind_recursive_cache_folder_count,
|
||||||
propfind_recursive_cache_file_count);
|
ctx->propfind_recursive_cache_file_count);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,13 +20,15 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "csync_owncloud.h"
|
#include "csync_owncloud.h"
|
||||||
|
#include "csync_owncloud_private.h"
|
||||||
|
|
||||||
#include "csync_misc.h"
|
#include "csync_misc.h"
|
||||||
|
|
||||||
void set_error_message( const char *msg )
|
void set_error_message( csync_owncloud_ctx_t *ctx, const char *msg )
|
||||||
{
|
{
|
||||||
SAFE_FREE(dav_session.error_string);
|
SAFE_FREE(ctx->dav_session.error_string);
|
||||||
if( msg )
|
if( msg )
|
||||||
dav_session.error_string = c_strdup(msg);
|
ctx->dav_session.error_string = c_strdup(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_errno_from_http_errcode( int err ) {
|
void set_errno_from_http_errcode( int err ) {
|
||||||
|
@ -104,12 +106,12 @@ void set_errno_from_http_errcode( int err ) {
|
||||||
errno = new_errno;
|
errno = new_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_result_code_from_session() {
|
int http_result_code_from_session(csync_owncloud_ctx_t *ctx) {
|
||||||
const char *p = ne_get_error( dav_session.ctx );
|
const char *p = ne_get_error( ctx->dav_session.ctx );
|
||||||
char *q;
|
char *q;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
set_error_message(p); /* remember the error message */
|
set_error_message(ctx, p); /* remember the error message */
|
||||||
|
|
||||||
err = strtol(p, &q, 10);
|
err = strtol(p, &q, 10);
|
||||||
if (p == q) {
|
if (p == q) {
|
||||||
|
@ -118,8 +120,8 @@ int http_result_code_from_session() {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_errno_from_session() {
|
void set_errno_from_session(csync_owncloud_ctx_t *ctx) {
|
||||||
int err = http_result_code_from_session();
|
int err = http_result_code_from_session(ctx);
|
||||||
|
|
||||||
if( err == EIO || err == ERRNO_ERROR_STRING) {
|
if( err == EIO || err == ERRNO_ERROR_STRING) {
|
||||||
errno = err;
|
errno = err;
|
||||||
|
@ -128,7 +130,7 @@ void set_errno_from_session() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_errno_from_neon_errcode( int neon_code ) {
|
void set_errno_from_neon_errcode(csync_owncloud_ctx_t *ctx, int neon_code ) {
|
||||||
|
|
||||||
if( neon_code != NE_OK ) {
|
if( neon_code != NE_OK ) {
|
||||||
DEBUG_WEBDAV("Neon error code was %d", neon_code);
|
DEBUG_WEBDAV("Neon error code was %d", neon_code);
|
||||||
|
@ -137,7 +139,7 @@ void set_errno_from_neon_errcode( int neon_code ) {
|
||||||
switch(neon_code) {
|
switch(neon_code) {
|
||||||
case NE_OK: /* Success, but still the possiblity of problems */
|
case NE_OK: /* Success, but still the possiblity of problems */
|
||||||
case NE_ERROR: /* Generic error; use ne_get_error(session) for message */
|
case NE_ERROR: /* Generic error; use ne_get_error(session) for message */
|
||||||
set_errno_from_session(); /* Something wrong with http communication */
|
set_errno_from_session(ctx); /* Something wrong with http communication */
|
||||||
break;
|
break;
|
||||||
case NE_LOOKUP: /* Server or proxy hostname lookup failed */
|
case NE_LOOKUP: /* Server or proxy hostname lookup failed */
|
||||||
errno = ERRNO_LOOKUP_ERROR;
|
errno = ERRNO_LOOKUP_ERROR;
|
||||||
|
@ -279,19 +281,9 @@ time_t oc_httpdate_parse( const char *date ) {
|
||||||
/*
|
/*
|
||||||
* helper: convert a resource struct to file_stat struct.
|
* helper: convert a resource struct to file_stat struct.
|
||||||
*/
|
*/
|
||||||
csync_vio_file_stat_t *resourceToFileStat( struct resource *res )
|
void resourceToFileStat(csync_vio_file_stat_t *lfs, struct resource *res )
|
||||||
{
|
{
|
||||||
csync_vio_file_stat_t *lfs = NULL;
|
ZERO_STRUCTP(lfs);
|
||||||
|
|
||||||
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 );
|
lfs->name = c_strdup( res->name );
|
||||||
|
|
||||||
|
@ -306,17 +298,29 @@ csync_vio_file_stat_t *resourceToFileStat( struct resource *res )
|
||||||
DEBUG_WEBDAV("ERROR: Unknown resource type %d", res->type);
|
DEBUG_WEBDAV("ERROR: Unknown resource type %d", res->type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME Those are defaults, we'll have to use the real ownCloud WebDAV permissions soon
|
||||||
|
lfs->mode = _stat_perms( lfs->type );
|
||||||
|
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS;
|
||||||
|
|
||||||
lfs->mtime = res->modtime;
|
lfs->mtime = res->modtime;
|
||||||
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME;
|
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME;
|
||||||
lfs->size = res->size;
|
lfs->size = res->size;
|
||||||
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
|
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
|
||||||
if( res->md5 ) {
|
if( res->md5 ) {
|
||||||
lfs->etag = c_strdup(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);
|
csync_vio_file_stat_set_file_id(lfs, res->file_id);
|
||||||
|
|
||||||
return lfs;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* WebDAV does not deliver permissions. Set a default here. */
|
/* WebDAV does not deliver permissions. Set a default here. */
|
||||||
|
@ -339,3 +343,93 @@ int _stat_perms( int type ) {
|
||||||
return ret;
|
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);
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -61,18 +61,6 @@
|
||||||
*/
|
*/
|
||||||
#define MAX_DEPTH 50
|
#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_INIT 1 << 0
|
||||||
#define CSYNC_STATUS_UPDATE 1 << 1
|
#define CSYNC_STATUS_UPDATE 1 << 1
|
||||||
#define CSYNC_STATUS_RECONCILE 1 << 2
|
#define CSYNC_STATUS_RECONCILE 1 << 2
|
||||||
|
@ -90,6 +78,8 @@ enum csync_replica_e {
|
||||||
|
|
||||||
typedef struct csync_file_stat_s csync_file_stat_t;
|
typedef struct csync_file_stat_s csync_file_stat_t;
|
||||||
|
|
||||||
|
struct csync_owncloud_ctx_s; // csync_owncloud.c
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief csync public structure
|
* @brief csync public structure
|
||||||
*/
|
*/
|
||||||
|
@ -162,6 +152,8 @@ struct csync_s {
|
||||||
volatile int abort;
|
volatile int abort;
|
||||||
void *rename_info;
|
void *rename_info;
|
||||||
int read_from_db_disabled;
|
int read_from_db_disabled;
|
||||||
|
|
||||||
|
struct csync_owncloud_ctx_s *owncloud_context;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -185,6 +177,9 @@ struct csync_file_stat_s {
|
||||||
char *destpath; /* for renames */
|
char *destpath; /* for renames */
|
||||||
const char *etag;
|
const char *etag;
|
||||||
char file_id[FILE_ID_BUF_SIZE+1]; /* the ownCloud file id is fixed width of 21 byte. */
|
char file_id[FILE_ID_BUF_SIZE+1]; /* the ownCloud file id is fixed width of 21 byte. */
|
||||||
|
char *directDownloadUrl;
|
||||||
|
char *directDownloadCookies;
|
||||||
|
|
||||||
CSYNC_STATUS error_status;
|
CSYNC_STATUS error_status;
|
||||||
|
|
||||||
enum csync_instructions_e instruction; /* u32 */
|
enum csync_instructions_e instruction; /* u32 */
|
||||||
|
|
|
@ -361,8 +361,6 @@ out:
|
||||||
st->mode = fs->mode;
|
st->mode = fs->mode;
|
||||||
st->size = fs->size;
|
st->size = fs->size;
|
||||||
st->modtime = fs->mtime;
|
st->modtime = fs->mtime;
|
||||||
st->uid = fs->uid;
|
|
||||||
st->gid = fs->gid;
|
|
||||||
st->nlink = fs->nlink;
|
st->nlink = fs->nlink;
|
||||||
st->type = type;
|
st->type = type;
|
||||||
st->etag = NULL;
|
st->etag = NULL;
|
||||||
|
@ -371,6 +369,15 @@ out:
|
||||||
st->etag = c_strdup(fs->etag);
|
st->etag = c_strdup(fs->etag);
|
||||||
}
|
}
|
||||||
csync_vio_set_file_id(st->file_id, fs->file_id);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fastout: /* target if the file information is read from database into st */
|
fastout: /* target if the file information is read from database into st */
|
||||||
st->phash = h;
|
st->phash = h;
|
||||||
|
@ -586,9 +593,14 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* == see if really stat has to be called. */
|
/* Only for the local replica we have to stat(), for the remote one we have all data already */
|
||||||
fs = csync_vio_file_stat_new();
|
if (ctx->replica == LOCAL_REPLICA) {
|
||||||
res = csync_vio_stat(ctx, filename, fs);
|
fs = csync_vio_file_stat_new();
|
||||||
|
res = csync_vio_stat(ctx, filename, fs);
|
||||||
|
} else {
|
||||||
|
fs = dirent;
|
||||||
|
res = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if( res == 0) {
|
if( res == 0) {
|
||||||
switch (fs->type) {
|
switch (fs->type) {
|
||||||
|
@ -643,7 +655,10 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
||||||
previous_fs->child_modified = ctx->current_fs->child_modified;
|
previous_fs->child_modified = ctx->current_fs->child_modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
csync_vio_file_stat_destroy(fs);
|
/* 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);
|
||||||
|
}
|
||||||
|
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
if (CSYNC_STATUS_IS_OK(ctx->status_code)) {
|
if (CSYNC_STATUS_IS_OK(ctx->status_code)) {
|
||||||
|
|
|
@ -128,59 +128,6 @@ void csync_win32_set_file_hidden( const char *file, bool h ) {
|
||||||
#endif
|
#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
|
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*));
|
||||||
void set_csync_file_locked_or_open_ext(bool (*f) (const char*)) {
|
void set_csync_file_locked_or_open_ext(bool (*f) (const char*)) {
|
||||||
|
|
|
@ -32,8 +32,5 @@ void csync_memstat_check(void);
|
||||||
|
|
||||||
void csync_win32_set_file_hidden( const char *file, bool hidden );
|
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);
|
bool csync_file_locked_or_open( const char *dir, const char *fname);
|
||||||
#endif /* _CSYNC_UTIL_H */
|
#endif /* _CSYNC_UTIL_H */
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include "csync_private.h"
|
#include "csync_private.h"
|
||||||
#include "csync_util.h"
|
#include "csync_util.h"
|
||||||
|
@ -44,7 +45,7 @@ csync_vio_handle_t *csync_vio_opendir(CSYNC *ctx, const char *name) {
|
||||||
if(ctx->remote.read_from_db) {
|
if(ctx->remote.read_from_db) {
|
||||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Read from db flag is true, should not!" );
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Read from db flag is true, should not!" );
|
||||||
}
|
}
|
||||||
return owncloud_opendir(name);
|
return owncloud_opendir(ctx, name);
|
||||||
break;
|
break;
|
||||||
case LOCAL_REPLICA:
|
case LOCAL_REPLICA:
|
||||||
return csync_vio_local_opendir(name);
|
return csync_vio_local_opendir(name);
|
||||||
|
@ -69,7 +70,7 @@ int csync_vio_closedir(CSYNC *ctx, csync_vio_handle_t *dhandle) {
|
||||||
if( ctx->remote.read_from_db ) {
|
if( ctx->remote.read_from_db ) {
|
||||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Remote ReadFromDb is true, should not!");
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Remote ReadFromDb is true, should not!");
|
||||||
}
|
}
|
||||||
rc = owncloud_closedir(dhandle);
|
rc = owncloud_closedir(ctx, dhandle);
|
||||||
break;
|
break;
|
||||||
case LOCAL_REPLICA:
|
case LOCAL_REPLICA:
|
||||||
rc = csync_vio_local_closedir(dhandle);
|
rc = csync_vio_local_closedir(dhandle);
|
||||||
|
@ -87,7 +88,7 @@ csync_vio_file_stat_t *csync_vio_readdir(CSYNC *ctx, csync_vio_handle_t *dhandle
|
||||||
if( ctx->remote.read_from_db ) {
|
if( ctx->remote.read_from_db ) {
|
||||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Remote readfromdb is true, should not!");
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Remote readfromdb is true, should not!");
|
||||||
}
|
}
|
||||||
return owncloud_readdir(dhandle);
|
return owncloud_readdir(ctx, dhandle);
|
||||||
break;
|
break;
|
||||||
case LOCAL_REPLICA:
|
case LOCAL_REPLICA:
|
||||||
return csync_vio_local_readdir(dhandle);
|
return csync_vio_local_readdir(dhandle);
|
||||||
|
@ -106,7 +107,8 @@ int csync_vio_stat(CSYNC *ctx, const char *uri, csync_vio_file_stat_t *buf) {
|
||||||
|
|
||||||
switch(ctx->replica) {
|
switch(ctx->replica) {
|
||||||
case REMOTE_REPLICA:
|
case REMOTE_REPLICA:
|
||||||
rc = owncloud_stat(uri, buf);
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "ERROR: Cannot call remote stat, not implemented");
|
||||||
|
assert(ctx->replica != REMOTE_REPLICA);
|
||||||
break;
|
break;
|
||||||
case LOCAL_REPLICA:
|
case LOCAL_REPLICA:
|
||||||
rc = csync_vio_local_stat(uri, buf);
|
rc = csync_vio_local_stat(uri, buf);
|
||||||
|
@ -121,21 +123,9 @@ int csync_vio_stat(CSYNC *ctx, const char *uri, csync_vio_file_stat_t *buf) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
char *csync_vio_get_status_string(CSYNC *ctx) {
|
char *csync_vio_get_status_string(CSYNC *ctx) {
|
||||||
if(ctx->error_string) {
|
if(ctx->error_string) {
|
||||||
return ctx->error_string;
|
return ctx->error_string;
|
||||||
}
|
}
|
||||||
return owncloud_error_string();
|
return owncloud_error_string(ctx);
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,10 +39,7 @@ 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_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);
|
char *csync_vio_get_status_string(CSYNC *ctx);
|
||||||
|
|
||||||
int csync_vio_commit(CSYNC *ctx);
|
|
||||||
|
|
||||||
#endif /* _CSYNC_VIO_H */
|
#endif /* _CSYNC_VIO_H */
|
||||||
|
|
|
@ -22,14 +22,8 @@
|
||||||
#include "vio/csync_vio_file_stat.h"
|
#include "vio/csync_vio_file_stat.h"
|
||||||
|
|
||||||
csync_vio_file_stat_t *csync_vio_file_stat_new(void) {
|
csync_vio_file_stat_t *csync_vio_file_stat_new(void) {
|
||||||
csync_vio_file_stat_t *file_stat = NULL;
|
csync_vio_file_stat_t *file_stat = (csync_vio_file_stat_t *) c_malloc(sizeof(csync_vio_file_stat_t));
|
||||||
|
ZERO_STRUCTP(file_stat);
|
||||||
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;
|
return file_stat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,15 +33,11 @@ void csync_vio_file_stat_destroy(csync_vio_file_stat_t *file_stat) {
|
||||||
return;
|
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) {
|
if (file_stat->fields & CSYNC_VIO_FILE_STAT_FIELDS_ETAG) {
|
||||||
SAFE_FREE(file_stat->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->name);
|
||||||
SAFE_FREE(file_stat);
|
SAFE_FREE(file_stat);
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,42 +62,35 @@ enum csync_vio_file_stat_fields_e {
|
||||||
CSYNC_VIO_FILE_STAT_FIELDS_INODE = 1 << 4,
|
CSYNC_VIO_FILE_STAT_FIELDS_INODE = 1 << 4,
|
||||||
CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT = 1 << 5,
|
CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT = 1 << 5,
|
||||||
CSYNC_VIO_FILE_STAT_FIELDS_SIZE = 1 << 6,
|
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_COUNT = 1 << 7, /* will be removed */
|
||||||
CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_SIZE = 1 << 8, /* 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_ATIME = 1 << 9,
|
||||||
CSYNC_VIO_FILE_STAT_FIELDS_MTIME = 1 << 10,
|
CSYNC_VIO_FILE_STAT_FIELDS_MTIME = 1 << 10,
|
||||||
CSYNC_VIO_FILE_STAT_FIELDS_CTIME = 1 << 11,
|
CSYNC_VIO_FILE_STAT_FIELDS_CTIME = 1 << 11,
|
||||||
CSYNC_VIO_FILE_STAT_FIELDS_SYMLINK_NAME = 1 << 12,
|
// CSYNC_VIO_FILE_STAT_FIELDS_SYMLINK_NAME = 1 << 12,
|
||||||
CSYNC_VIO_FILE_STAT_FIELDS_CHECKSUM = 1 << 13,
|
// CSYNC_VIO_FILE_STAT_FIELDS_CHECKSUM = 1 << 13,
|
||||||
CSYNC_VIO_FILE_STAT_FIELDS_ACL = 1 << 14,
|
// CSYNC_VIO_FILE_STAT_FIELDS_ACL = 1 << 14,
|
||||||
CSYNC_VIO_FILE_STAT_FIELDS_UID = 1 << 15,
|
// CSYNC_VIO_FILE_STAT_FIELDS_UID = 1 << 15,
|
||||||
CSYNC_VIO_FILE_STAT_FIELDS_GID = 1 << 16,
|
// CSYNC_VIO_FILE_STAT_FIELDS_GID = 1 << 16,
|
||||||
CSYNC_VIO_FILE_STAT_FIELDS_ETAG = 1 << 17,
|
CSYNC_VIO_FILE_STAT_FIELDS_ETAG = 1 << 17,
|
||||||
CSYNC_VIO_FILE_STAT_FIELDS_FILE_ID = 1 << 18
|
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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct csync_vio_file_stat_s {
|
struct csync_vio_file_stat_s {
|
||||||
union {
|
|
||||||
char *symlink_name;
|
|
||||||
char *checksum;
|
|
||||||
} u;
|
|
||||||
|
|
||||||
void *acl;
|
|
||||||
char *name;
|
char *name;
|
||||||
char *etag;
|
char *etag;
|
||||||
char file_id[FILE_ID_BUF_SIZE+1];
|
char file_id[FILE_ID_BUF_SIZE+1];
|
||||||
|
char *directDownloadUrl;
|
||||||
uid_t uid;
|
char *directDownloadCookies;
|
||||||
gid_t gid;
|
|
||||||
|
|
||||||
time_t atime;
|
time_t atime;
|
||||||
time_t mtime;
|
time_t mtime;
|
||||||
time_t ctime;
|
time_t ctime;
|
||||||
|
|
||||||
int64_t size;
|
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;
|
mode_t mode;
|
||||||
|
|
||||||
|
@ -109,10 +102,6 @@ struct csync_vio_file_stat_s {
|
||||||
enum csync_vio_file_type_e type;
|
enum csync_vio_file_type_e type;
|
||||||
|
|
||||||
enum csync_vio_file_flags_e flags;
|
enum csync_vio_file_flags_e flags;
|
||||||
|
|
||||||
void *reserved1;
|
|
||||||
void *reserved2;
|
|
||||||
void *reserved3;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
csync_vio_file_stat_t *csync_vio_file_stat_new(void);
|
csync_vio_file_stat_t *csync_vio_file_stat_new(void);
|
||||||
|
|
|
@ -331,11 +331,6 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
|
||||||
buf->inode = sb.st_ino;
|
buf->inode = sb.st_ino;
|
||||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_INODE;
|
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->atime = sb.st_atime;
|
||||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME;
|
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME;
|
||||||
|
|
||||||
|
@ -348,12 +343,6 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
|
||||||
buf->nlink = sb.st_nlink;
|
buf->nlink = sb.st_nlink;
|
||||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT;
|
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->size = sb.st_size;
|
||||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
|
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,12 @@ protected:
|
||||||
QNetworkRequest req(request);
|
QNetworkRequest req(request);
|
||||||
req.setRawHeader(QByteArray("Authorization"), QByteArray("Basic ") + credHash);
|
req.setRawHeader(QByteArray("Authorization"), QByteArray("Basic ") + credHash);
|
||||||
//qDebug() << "Request for " << req.url() << "with authorization" << QByteArray::fromBase64(credHash);
|
//qDebug() << "Request for " << req.url() << "with authorization" << QByteArray::fromBase64(credHash);
|
||||||
req.setRawHeader(QByteArray("Cookie"), _cred->_token.toLocal8Bit());
|
|
||||||
|
// Append token cookie
|
||||||
|
QList<QNetworkCookie> cookies = request.header(QNetworkRequest::CookieHeader).value<QList<QNetworkCookie> >();
|
||||||
|
cookies.append(QNetworkCookie::parseCookies(_cred->_token.toUtf8()));
|
||||||
|
req.setHeader(QNetworkRequest::CookieHeader, QVariant::fromValue(cookies));
|
||||||
|
|
||||||
return MirallAccessManager::createRequest(op, req, outgoingData);
|
return MirallAccessManager::createRequest(op, req, outgoingData);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
|
@ -112,7 +117,7 @@ void TokenCredentials::syncContextPreInit (CSYNC* ctx)
|
||||||
|
|
||||||
void TokenCredentials::syncContextPreStart (CSYNC* ctx)
|
void TokenCredentials::syncContextPreStart (CSYNC* ctx)
|
||||||
{
|
{
|
||||||
csync_set_module_property(ctx, "session_key", _token.toLocal8Bit().data());
|
csync_set_module_property(ctx, "session_key", _token.toUtf8().data());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TokenCredentials::changed(AbstractCredentials* credentials) const
|
bool TokenCredentials::changed(AbstractCredentials* credentials) const
|
||||||
|
|
|
@ -494,6 +494,10 @@ void PropagateDownloadFileLegacy::start()
|
||||||
_propagator->_journal->commit("download file 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 */
|
/* actually do the request */
|
||||||
int retry = 0;
|
int retry = 0;
|
||||||
|
|
||||||
|
|
|
@ -358,13 +358,38 @@ void PropagateUploadFileQNAM::abort()
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// DOES NOT take owncership of the device.
|
||||||
|
GETFileJob::GETFileJob(Account* account, const QString& path, QIODevice *device,
|
||||||
|
const QMap<QByteArray, QByteArray> &headers, QByteArray expectedEtagForResume,
|
||||||
|
QObject* parent)
|
||||||
|
: AbstractNetworkJob(account, path, parent),
|
||||||
|
_device(device), _headers(headers), _expectedEtagForResume(expectedEtagForResume),
|
||||||
|
_errorStatus(SyncFileItem::NoStatus)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
GETFileJob::GETFileJob(Account* account, const QUrl& url, QIODevice *device,
|
||||||
|
const QMap<QByteArray, QByteArray> &headers,
|
||||||
|
QObject* parent)
|
||||||
|
: AbstractNetworkJob(account, url.toEncoded(), parent),
|
||||||
|
_device(device), _headers(headers),
|
||||||
|
_errorStatus(SyncFileItem::NoStatus), _directDownloadUrl(url)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void GETFileJob::start() {
|
void GETFileJob::start() {
|
||||||
QNetworkRequest req;
|
QNetworkRequest req;
|
||||||
for(QMap<QByteArray, QByteArray>::const_iterator it = _headers.begin(); it != _headers.end(); ++it) {
|
for(QMap<QByteArray, QByteArray>::const_iterator it = _headers.begin(); it != _headers.end(); ++it) {
|
||||||
req.setRawHeader(it.key(), it.value());
|
req.setRawHeader(it.key(), it.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
setReply(davRequest("GET", path(), req));
|
if (_directDownloadUrl.isEmpty()) {
|
||||||
|
setReply(davRequest("GET", path(), req));
|
||||||
|
} else {
|
||||||
|
// Use direct URL
|
||||||
|
setReply(davRequest("GET", _directDownloadUrl, req));
|
||||||
|
}
|
||||||
setupConnections(reply());
|
setupConnections(reply());
|
||||||
|
|
||||||
if( reply()->error() != QNetworkReply::NoError ) {
|
if( reply()->error() != QNetworkReply::NoError ) {
|
||||||
|
@ -386,17 +411,21 @@ void GETFileJob::slotMetaDataChanged()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray etag = parseEtag(reply()->rawHeader("Etag"));
|
_etag = parseEtag(reply()->rawHeader("Etag"));
|
||||||
|
if (!_directDownloadUrl.isEmpty() && !_etag.isEmpty()) {
|
||||||
if (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()) {
|
||||||
qDebug() << Q_FUNC_INFO << "No E-Tag reply by server, considering it invalid";
|
qDebug() << Q_FUNC_INFO << "No E-Tag reply by server, considering it invalid";
|
||||||
_errorString = tr("No E-Tag received from server, check Proxy/Gateway");
|
_errorString = tr("No E-Tag received from server, check Proxy/Gateway");
|
||||||
_errorStatus = SyncFileItem::NormalError;
|
_errorStatus = SyncFileItem::NormalError;
|
||||||
reply()->abort();
|
reply()->abort();
|
||||||
return;
|
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!"
|
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.");
|
_errorString = tr("We received a different E-Tag for resuming. Retrying next time.");
|
||||||
_errorStatus = SyncFileItem::NormalError;
|
_errorStatus = SyncFileItem::NormalError;
|
||||||
reply()->abort();
|
reply()->abort();
|
||||||
|
@ -431,6 +460,13 @@ void GETFileJob::slotReadyRead()
|
||||||
resetTimeout();
|
resetTimeout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GETFileJob::slotTimeout()
|
||||||
|
{
|
||||||
|
_errorString = tr("Connection Timeout");
|
||||||
|
_errorStatus = SyncFileItem::FatalError;
|
||||||
|
reply()->abort();
|
||||||
|
}
|
||||||
|
|
||||||
void PropagateDownloadFileQNAM::start()
|
void PropagateDownloadFileQNAM::start()
|
||||||
{
|
{
|
||||||
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
|
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
|
||||||
|
@ -438,7 +474,7 @@ void PropagateDownloadFileQNAM::start()
|
||||||
|
|
||||||
qDebug() << Q_FUNC_INFO << _item._file << _propagator->_activeJobs;
|
qDebug() << Q_FUNC_INFO << _item._file << _propagator->_activeJobs;
|
||||||
|
|
||||||
// do a case clash check.
|
// do a klaas' case clash check.
|
||||||
if( _propagator->localFileNameClash(_item._file) ) {
|
if( _propagator->localFileNameClash(_item._file) ) {
|
||||||
done( SyncFileItem::NormalError, tr("File %1 can not be downloaded because of a local file name clash!")
|
done( SyncFileItem::NormalError, tr("File %1 can not be downloaded because of a local file name clash!")
|
||||||
.arg(QDir::toNativeSeparators(_item._file)) );
|
.arg(QDir::toNativeSeparators(_item._file)) );
|
||||||
|
@ -490,8 +526,6 @@ void PropagateDownloadFileQNAM::start()
|
||||||
|
|
||||||
|
|
||||||
QMap<QByteArray, QByteArray> headers;
|
QMap<QByteArray, QByteArray> headers;
|
||||||
/* Allow compressed content by setting the header */
|
|
||||||
//headers["Accept-Encoding"] = "gzip";
|
|
||||||
|
|
||||||
if (_tmpFile.size() > 0) {
|
if (_tmpFile.size() > 0) {
|
||||||
quint64 done = _tmpFile.size();
|
quint64 done = _tmpFile.size();
|
||||||
|
@ -506,9 +540,22 @@ void PropagateDownloadFileQNAM::start()
|
||||||
_startSize = done;
|
_startSize = done;
|
||||||
}
|
}
|
||||||
|
|
||||||
_job = new GETFileJob(AccountManager::instance()->account(),
|
if (_item._directDownloadUrl.isEmpty()) {
|
||||||
_propagator->_remoteFolder + _item._file,
|
// Normal job, download from oC instance
|
||||||
&_tmpFile, headers, expectedEtagForResume);
|
_job = new GETFileJob(AccountManager::instance()->account(),
|
||||||
|
_propagator->_remoteFolder + _item._file,
|
||||||
|
&_tmpFile, headers, expectedEtagForResume);
|
||||||
|
} 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);
|
||||||
|
qDebug() << Q_FUNC_INFO << "directDownloadUrl given for " << _item._file << _item._directDownloadUrl;
|
||||||
|
}
|
||||||
_job->setTimeout(_propagator->httpTimeout() * 1000);
|
_job->setTimeout(_propagator->httpTimeout() * 1000);
|
||||||
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotGetFinished()));
|
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotGetFinished()));
|
||||||
connect(_job, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(slotDownloadProgress(qint64,qint64)));
|
connect(_job, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(slotDownloadProgress(qint64,qint64)));
|
||||||
|
@ -546,7 +593,11 @@ void PropagateDownloadFileQNAM::slotGetFinished()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_item._etag = parseEtag(job->reply()->rawHeader("Etag"));
|
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._requestDuration = job->duration();
|
_item._requestDuration = job->duration();
|
||||||
_item._responseTimeStamp = job->responseTimestamp();
|
_item._responseTimeStamp = job->responseTimestamp();
|
||||||
|
|
||||||
|
@ -628,13 +679,4 @@ void PropagateDownloadFileQNAM::abort()
|
||||||
_job->reply()->abort();
|
_job->reply()->abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GETFileJob::slotTimeout()
|
|
||||||
{
|
|
||||||
_errorString = tr("Connection Timeout");
|
|
||||||
_errorStatus = SyncFileItem::FatalError;
|
|
||||||
reply()->abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,15 +110,18 @@ class GETFileJob : public AbstractNetworkJob {
|
||||||
QString _errorString;
|
QString _errorString;
|
||||||
QByteArray _expectedEtagForResume;
|
QByteArray _expectedEtagForResume;
|
||||||
SyncFileItem::Status _errorStatus;
|
SyncFileItem::Status _errorStatus;
|
||||||
|
QUrl _directDownloadUrl;
|
||||||
|
QByteArray _etag;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// DOES NOT take owncership of the device.
|
// DOES NOT take owncership of the device.
|
||||||
explicit GETFileJob(Account* account, const QString& path, QIODevice *device,
|
explicit GETFileJob(Account* account, const QString& path, QIODevice *device,
|
||||||
const QMap<QByteArray, QByteArray> &headers, QByteArray expectedEtagForResume,
|
const QMap<QByteArray, QByteArray> &headers, QByteArray expectedEtagForResume,
|
||||||
QObject* parent = 0)
|
QObject* parent = 0);
|
||||||
: AbstractNetworkJob(account, path, parent),
|
// For directDownloadUrl:
|
||||||
_device(device), _headers(headers), _expectedEtagForResume(expectedEtagForResume),
|
explicit GETFileJob(Account* account, const QUrl& url, QIODevice *device,
|
||||||
_errorStatus(SyncFileItem::NoStatus) {}
|
const QMap<QByteArray, QByteArray> &headers,
|
||||||
|
QObject* parent = 0);
|
||||||
|
|
||||||
virtual void start();
|
virtual void start();
|
||||||
virtual bool finished() {
|
virtual bool finished() {
|
||||||
|
@ -134,6 +137,8 @@ public:
|
||||||
|
|
||||||
virtual void slotTimeout();
|
virtual void slotTimeout();
|
||||||
|
|
||||||
|
QByteArray &etag() { return _etag; }
|
||||||
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void finishedSignal();
|
void finishedSignal();
|
||||||
|
|
|
@ -263,6 +263,12 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
||||||
item._instruction = file->instruction;
|
item._instruction = file->instruction;
|
||||||
item._direction = SyncFileItem::None;
|
item._direction = SyncFileItem::None;
|
||||||
item._fileId = file->file_id;
|
item._fileId = file->file_id;
|
||||||
|
if (file->directDownloadUrl) {
|
||||||
|
item._directDownloadUrl = QString::fromUtf8( file->directDownloadUrl );
|
||||||
|
}
|
||||||
|
if (file->directDownloadCookies) {
|
||||||
|
item._directDownloadCookies = QString::fromUtf8( file->directDownloadCookies );
|
||||||
|
}
|
||||||
|
|
||||||
// record the seen files to be able to clean the journal later
|
// record the seen files to be able to clean the journal later
|
||||||
_seenFiles[item._file] = QString();
|
_seenFiles[item._file] = QString();
|
||||||
|
@ -287,7 +293,6 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
||||||
Q_ASSERT("Non handled error-status");
|
Q_ASSERT("Non handled error-status");
|
||||||
/* No error string */
|
/* No error string */
|
||||||
}
|
}
|
||||||
|
|
||||||
item._isDirectory = file->type == CSYNC_FTW_TYPE_DIR;
|
item._isDirectory = file->type == CSYNC_FTW_TYPE_DIR;
|
||||||
item._modtime = file->modtime;
|
item._modtime = file->modtime;
|
||||||
item._etag = file->etag;
|
item._etag = file->etag;
|
||||||
|
@ -464,7 +469,6 @@ void SyncEngine::startSync()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
csync_set_module_property(_csync_ctx, "csync_context", _csync_ctx);
|
|
||||||
csync_set_userdata(_csync_ctx, this);
|
csync_set_userdata(_csync_ctx, this);
|
||||||
// TODO: This should be a part of this method, but we don't have
|
// 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
|
// any way to get "session_key" module property from csync. Had we
|
||||||
|
|
|
@ -86,6 +86,8 @@ public:
|
||||||
quint64 _inode;
|
quint64 _inode;
|
||||||
bool _should_update_etag;
|
bool _should_update_etag;
|
||||||
QByteArray _fileId;
|
QByteArray _fileId;
|
||||||
|
QString _directDownloadUrl;
|
||||||
|
QString _directDownloadCookies;
|
||||||
bool _blacklistedInDb;
|
bool _blacklistedInDb;
|
||||||
|
|
||||||
// Variables usefull to report to the user
|
// Variables usefull to report to the user
|
||||||
|
|
Loading…
Reference in a new issue