owncloud: Use the new get/put methods of file up- and download.

This commit is contained in:
Klaas Freitag 2013-06-12 15:51:44 +02:00 committed by Andreas Schneider
parent a1628c8111
commit fb48813f15

View file

@ -36,6 +36,7 @@
#include <neon/ne_auth.h> #include <neon/ne_auth.h>
#include <neon/ne_dates.h> #include <neon/ne_dates.h>
#include <neon/ne_compress.h> #include <neon/ne_compress.h>
#include <neon/ne_redirect.h>
#include "c_lib.h" #include "c_lib.h"
#include "csync.h" #include "csync.h"
@ -97,20 +98,39 @@ struct listdir_context {
unsigned int result_count; /* number of elements stored in list */ unsigned int result_count; /* number of elements stored in list */
}; };
static void free_fetchCtx( struct listdir_context *ctx )
{
struct resource *newres, *res;
if( ! ctx ) return;
newres = ctx->list;
res = newres;
SAFE_FREE(ctx->target);
while( res ) {
SAFE_FREE(res->uri);
SAFE_FREE(res->name);
newres = res->next;
SAFE_FREE(res);
res = newres;
}
SAFE_FREE(ctx);
}
/* /*
* context to store info about a temp file for GET and PUT requests * context to store info about a temp file for GET and PUT requests
* which store the data in a local file to save memory and secure the * which store the data in a local file to save memory and secure the
* transmission. * transmission.
*/ */
struct transfer_context { struct transfer_context {
ne_request *req; /* the neon request */ ne_request *req; /* the neon request */
int fd; /* file descriptor of the file to read or write from */ int fd; /* file descriptor of the file to read or write from */
char *tmpFileName; /* the name of the temp file */ const char *method; /* the HTTP method, either PUT or GET */
size_t bytes_written; /* the amount of bytes written or read */ ne_decompress *decompress; /* the decompress context */
const char *method; /* the HTTP method, either PUT or GET */ char *url;
ne_decompress *decompress; /* the decompress context */
int fileWritten; /* flag to indicate that a buffer file was written for PUTs */
char *url;
}; };
/* Struct with the WebDAV session */ /* Struct with the WebDAV session */
@ -585,23 +605,105 @@ 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 int fetch_resource_list( const char *curi, static int fetch_resource_list( const char *uri,
int depth, int depth,
struct listdir_context *fetchCtx ) struct listdir_context *fetchCtx )
{ {
int ret = 0; int ret = 0;
ne_propfind_handler *hdl = NULL;
ne_request *request = NULL;
const char *content_type = NULL;
char *curi = NULL;
const ne_status *req_status = NULL;
if (!curi) curi = _cleanPath( uri );
return NE_ERROR;
/* do a propfind request and parse the results in the results function, set as callback */ if (!fetchCtx) {
ret = ne_simple_propfind( dav_session.ctx, curi, depth, ls_props, results, fetchCtx ); errno = ENOMEM;
SAFE_FREE(curi);
return -1;
}
fetchCtx->list = NULL;
fetchCtx->target = curi;
fetchCtx->currResource = NULL;
if( ret == NE_OK ) { /* do a propfind request and parse the results in the results function, set as callback */
DEBUG_WEBDAV("Simple propfind OK." ); hdl = ne_propfind_create(dav_session.ctx, curi, depth);
fetchCtx->currResource = fetchCtx->list;
if(hdl) {
ret = ne_propfind_named(hdl, ls_props, results, fetchCtx);
request = ne_propfind_get_request( hdl );
req_status = ne_get_status( request );
}
if( ret == NE_OK ) {
fetchCtx->currResource = fetchCtx->list;
/* Check the request status. */
if( req_status && req_status->klass != 2 ) {
set_errno_from_http_errcode(req_status->code);
DEBUG_WEBDAV("ERROR: Request failed: status %d (%s)", req_status->code,
req_status->reason_phrase);
ret = NE_CONNECT;
set_error_message(req_status->reason_phrase);
} }
return ret; DEBUG_WEBDAV("Simple propfind result code %d.", req_status->code);
} else {
if( ret == NE_ERROR && req_status->code == 404) {
errno = ENOENT;
} else {
set_errno_from_neon_errcode(ret);
}
}
if( ret == NE_OK ) {
/* Check the content type. If the server has a problem, ie. database is gone or such,
* the content type is not xml but a html error message. Stop on processing if it's
* not XML.
* FIXME: Generate user error message from the reply content.
*/
content_type = ne_get_response_header( request, "Content-Type" );
if( !(content_type && c_streq(content_type, "application/xml; charset=utf-8") ) ) {
ssize_t resp_size;
char buffer[4096];
ZERO_STRUCT(buffer);
DEBUG_WEBDAV("ERROR: Content type of propfind request not XML: %s.",
content_type ? content_type: "<empty>");
errno = ERRNO_WRONG_CONTENT;
set_error_message("Server error: PROPFIND reply is not XML formatted!");
/* Read the response buffer to log the actual problem. */
resp_size = ne_read_response_block(request, buffer, 4095);
DEBUG_WEBDAV("ERROR: Content was of size %ld: %s", resp_size, buffer );
ret = NE_CONNECT;
}
}
if( ret != NE_OK ) {
const char *err = NULL;
err = ne_get_error( dav_session.ctx );
DEBUG_WEBDAV("WRN: propfind named failed with %d, request error: %s", ret, err ? err : "<nil>");
}
if( hdl )
ne_propfind_destroy(hdl);
if( ret == NE_REDIRECT ) {
const ne_uri *redir_ne_uri = NULL;
char *redir_uri = NULL;
redir_ne_uri = ne_redirect_location(dav_session.ctx);
if( redir_ne_uri ) {
redir_uri = ne_uri_unparse(redir_ne_uri);
DEBUG_WEBDAV("Permanently moved to %s", redir_uri);
}
}
if( ret != NE_OK ) {
free_fetchCtx(fetchCtx);
return -1;
}
return 0;
} }
/* /*
@ -723,11 +825,12 @@ static int owncloud_stat(const char *uri, csync_vio_file_stat_t *buf) {
rc = fetch_resource_list( curi, NE_DEPTH_ONE, fetchCtx ); rc = fetch_resource_list( curi, NE_DEPTH_ONE, fetchCtx );
if( rc != NE_OK ) { if( rc != NE_OK ) {
if( errno != ENOENT ) {
set_errno_from_session(); set_errno_from_session();
}
DEBUG_WEBDAV("stat fails with errno %d", errno );
DEBUG_WEBDAV("stat fails with errno %d", errno ); return -1;
SAFE_FREE(fetchCtx);
return -1;
} }
if( fetchCtx ) { if( fetchCtx ) {
@ -772,58 +875,48 @@ static int owncloud_stat(const char *uri, csync_vio_file_stat_t *buf) {
return 0; return 0;
} }
/* Normally, this module uses get and put. But for creation of new files
* with owncloud_creat, write is still needed.
*/
static ssize_t owncloud_write(csync_vio_method_handle_t *fhandle, const void *buf, size_t count) { static ssize_t owncloud_write(csync_vio_method_handle_t *fhandle, const void *buf, size_t count) {
struct transfer_context *writeCtx = NULL;
size_t written = 0;
size_t bufWritten = 0;
if (fhandle == NULL) { struct transfer_context *writeCtx;
return -1; int rc = 0;
} int neon_stat;
const ne_status *status;
writeCtx = (struct transfer_context*) fhandle; writeCtx = (struct transfer_context*) fhandle;
/* check if there is space left in the mem buffer */ if (fhandle == NULL) {
if( writeCtx->bytes_written + count > PUT_BUFFER_SIZE ) { errno = EBADF;
if( writeCtx->fileWritten == 0 ) { rc = -1;
DEBUG_WEBDAV("Remaining Mem Buffer size to small, push to disk " }
"(current buf size %lu)",
(unsigned long) writeCtx->bytes_written);
}
/* write contents to disk */ ne_set_request_body_buffer(writeCtx->req, buf, count );
if( writeCtx->fd > -1 ) {
if( writeCtx->bytes_written > 0 ) {
/* there is something in the buffer already. Store to disk */
written = write( writeCtx->fd, _buffer, writeCtx->bytes_written ); /* Start the request. */
if( written != writeCtx->bytes_written ) { neon_stat = ne_request_dispatch( writeCtx->req );
DEBUG_WEBDAV("WRN: Written bytes from buffer not equal to count"); set_errno_from_neon_errcode( neon_stat );
}
/* reset the buffer counter */
writeCtx->bytes_written = 0;
}
/* also write the incoming memory buffer content to file */
if( count > 0 ) {
bufWritten = write( writeCtx->fd, buf, count );
if( bufWritten != count ) { status = ne_get_status( writeCtx->req );
DEBUG_WEBDAV("WRN: Written bytes not equal to count"); if( status->klass != 2 ) {
} DEBUG_WEBDAV("sendfile request failed with http status %d!", status->code);
} set_errno_from_http_errcode( status->code );
/* set a flag that file was used, needed in the close routine */ /* decide if soft error or hard error that stops the whole sync. */
writeCtx->fileWritten = 1; /* Currently all problems concerning one file are soft errors */
} else { if( status->klass == 4 /* Forbidden and stuff, soft error */ ) {
/* problem: the file descriptor is not valid. */ rc = 1;
DEBUG_WEBDAV("ERR: Not a valid file descriptor in write"); } else if( status->klass == 5 /* Server errors and such */ ) {
} rc = 1; /* No Abort on individual file errors. */
} else { } else {
/* still space in the buffer */ rc = 1;
memcpy( _buffer + writeCtx->bytes_written, buf, count );
writeCtx->bytes_written += count;
bufWritten = count;
} }
return bufWritten; } else {
DEBUG_WEBDAV("write request all ok, result code %d", status->code);
}
return rc;
} }
static int uncompress_reader(void *userdata, const char *buf, size_t len) static int uncompress_reader(void *userdata, const char *buf, size_t len)
@ -877,8 +970,10 @@ static void install_content_reader( ne_request *req, void *userdata, const ne_st
} }
enc = ne_get_response_header( req, "Content-Encoding" ); enc = ne_get_response_header( req, "Content-Encoding" );
DEBUG_WEBDAV("Content encoding ist <%s> with status %d", enc ? enc : "empty", if( status && status->code != 200 ) {
status ? status->code : -1 ); DEBUG_WEBDAV("Content encoding ist <%s> with status %d", enc ? enc : "empty",
status ? status->code : -1 );
}
if( enc && c_streq( enc, "gzip" )) { if( enc && c_streq( enc, "gzip" )) {
writeCtx->decompress = ne_decompress_reader( req, ne_accept_2xx, writeCtx->decompress = ne_decompress_reader( req, ne_accept_2xx,
@ -896,10 +991,14 @@ static char*_lastDir = NULL;
/* capabilities are currently: /* capabilities are currently:
* bool atomar_copy_support * bool atomar_copy_support
* bool put_support
* bool get_support
*/ */
static struct csync_vio_capabilities_s _owncloud_capabilities = { static struct csync_vio_capabilities_s _owncloud_capabilities = {
.atomar_copy_support = true, .atomar_copy_support = true,
.get_support = true,
.put_support = true,
}; };
static csync_vio_capabilities_t *owncloud_get_capabilities(void) static csync_vio_capabilities_t *owncloud_get_capabilities(void)
@ -943,35 +1042,33 @@ static csync_vio_method_handle_t *owncloud_open(const char *durl,
put = 1; put = 1;
} }
if( rc == NE_OK && put ) { if( rc == NE_OK && put ) {
/* check if the dir name exists. Otherwise return ENOENT */ /* check if the dir name exists. Otherwise return ENOENT */
dir = c_dirname( durl ); dir = c_dirname( durl );
if (dir == NULL) { if (dir == NULL) {
errno = ENOMEM; errno = ENOMEM;
return NULL; return NULL;
} }
DEBUG_WEBDAV("Stating directory %s", dir ); DEBUG_WEBDAV("Stating directory %s", dir );
if( c_streq( dir, _lastDir )) { if( c_streq( dir, _lastDir )) {
DEBUG_WEBDAV("Dir %s is there, we know it already.", dir); DEBUG_WEBDAV("Dir %s is there, we know it already.", dir);
} else { } else {
if( owncloud_stat( dir, (csync_vio_method_handle_t*)(&statBuf) ) == 0 ) { if( owncloud_stat( dir, (csync_vio_method_handle_t*)(&statBuf) ) == 0 ) {
DEBUG_WEBDAV("Directory of file to open exists."); DEBUG_WEBDAV("Directory of file to open exists.");
SAFE_FREE( _lastDir ); SAFE_FREE( _lastDir );
_lastDir = c_strdup(dir); _lastDir = c_strdup(dir);
} else { } else {
DEBUG_WEBDAV("Directory %s of file to open does NOT exist.", dir ); DEBUG_WEBDAV("Directory %s of file to open does NOT exist.", dir );
/* the directory does not exist. That is an ENOENT */ /* the directory does not exist. That is an ENOENT */
errno = ENOENT; errno = ENOENT;
SAFE_FREE( dir ); SAFE_FREE( dir );
return NULL; return NULL;
}
} }
}
} }
writeCtx = c_malloc( sizeof(struct transfer_context) ); writeCtx = c_malloc( sizeof(struct transfer_context) );
writeCtx->bytes_written = 0;
writeCtx->url = _cleanPath( durl ); writeCtx->url = _cleanPath( durl );
if( ! writeCtx->url ) { if( ! writeCtx->url ) {
@ -980,137 +1077,33 @@ static csync_vio_method_handle_t *owncloud_open(const char *durl,
rc = NE_ERROR; rc = NE_ERROR;
} }
if( rc == NE_OK ) {
/* open a temp file to store the incoming data */
#ifdef _WIN32
memset( tmpname, '\0', 13 );
gtp = GetTempPathW( PATH_MAX, winTmp );
winTmpUtf8 = c_utf8_from_locale( winTmp );
strcpy( getUrl, winTmpUtf8 );
DEBUG_WEBDAV("win32 tmp path: %s", getUrl);
if ( gtp > MAX_PATH || (gtp == 0) ) {
DEBUG_WEBDAV("Failed to compute Win32 tmp path", trying /tmp);
strcpy( getUrl, "/tmp/");
}
strcpy( tmpname, "csync.XXXXXX" );
if( c_tmpname( tmpname ) == 0 ) {
/* Set the windows file mode to Binary. */
_fmode = _O_BINARY;
/* append the tmp file name to tmp path */
strcat( getUrl, tmpname );
writeCtx->tmpFileName = c_strdup( getUrl );
/* Open the file finally. */
winUrlMB = c_utf8_to_locale( getUrl );
/* check if the file exists by chance. */
if( _tstat( winUrlMB, &sb ) == 0 ) {
/* the file exists. Remove it! */
_tunlink( winUrlMB );
}
writeCtx->fd = _topen( winUrlMB, O_RDWR | O_CREAT | O_EXCL, 0600 );
/* free the extra bytes */
c_free_locale_string( winUrlMB );
c_free_locale_string( winTmpUtf8 );
} else {
writeCtx->fd = -1;
}
#else
writeCtx->tmpFileName = c_strdup( "/tmp/csync.XXXXXX" );
writeCtx->fd = mkstemp( writeCtx->tmpFileName );
#endif
DEBUG_WEBDAV("opening temp directory %s: %d", writeCtx->tmpFileName, writeCtx->fd );
if( writeCtx->fd == -1 ) {
DEBUG_WEBDAV("Failed to open temp file, errno = %d", errno );
rc = NE_ERROR;
/* errno is set by the mkstemp call above. */
}
}
if( rc == NE_OK && put) { if( rc == NE_OK && put) {
DEBUG_WEBDAV("PUT request on %s!", writeCtx->url); DEBUG_WEBDAV("PUT request on %s!", writeCtx->url);
/* reset the write buffer */
writeCtx->bytes_written = 0;
writeCtx->fileWritten = 0; /* flag to indicate if contents was pushed to file */
writeCtx->req = ne_request_create(dav_session.ctx, "PUT", writeCtx->url); writeCtx->req = ne_request_create(dav_session.ctx, "PUT", writeCtx->url);
writeCtx->method = "PUT"; writeCtx->method = "PUT";
} }
if( rc == NE_OK && ! put ) { if( rc == NE_OK && ! put ) {
writeCtx->req = 0; writeCtx->req = 0;
writeCtx->method = "GET"; writeCtx->method = "GET";
/* Download the data into a local temp file. */
/* the download via the get function requires a full uri */ /* the download via the get function requires a full uri */
snprintf( getUrl, PATH_MAX, "%s://%s%s", ne_get_scheme( dav_session.ctx), snprintf( getUrl, PATH_MAX, "%s://%s%s", ne_get_scheme( dav_session.ctx),
ne_get_server_hostport( dav_session.ctx ), writeCtx->url ); ne_get_server_hostport( dav_session.ctx ), writeCtx->url );
DEBUG_WEBDAV("GET request on %s", getUrl ); DEBUG_WEBDAV("GET request on %s", getUrl );
#define WITH_HTTP_COMPRESSION
#ifdef WITH_HTTP_COMPRESSION
writeCtx->req = ne_request_create( dav_session.ctx, "GET", getUrl ); writeCtx->req = ne_request_create( dav_session.ctx, "GET", getUrl );
/* Allow compressed content by setting the header */
ne_add_request_header( writeCtx->req, "Accept-Encoding", "gzip,deflate" );
/* hook called before the content is parsed to set the correct reader,
* either the compressed- or uncompressed reader.
*/
ne_hook_post_headers( dav_session.ctx, install_content_reader, writeCtx );
/* Call the progress callback */ /* Call the progress callback */
if (_file_progress_cb) { if (_file_progress_cb) {
ne_set_notifier(dav_session.ctx, ne_notify_status_cb, writeCtx); ne_set_notifier(dav_session.ctx, ne_notify_status_cb, writeCtx);
_file_progress_cb( writeCtx->url, CSYNC_NOTIFY_START_DOWNLOAD, 0 , 0, _userdata); _file_progress_cb( writeCtx->url, CSYNC_NOTIFY_START_DOWNLOAD, 0 , 0, _userdata);
} }
/* actually do the request */
rc = ne_request_dispatch(writeCtx->req );
/* possible return codes are:
* NE_OK, NE_AUTH, NE_CONNECT, NE_TIMEOUT, NE_ERROR (from ne_request.h)
*/
if( rc != NE_OK || (rc == NE_OK && ne_get_status(writeCtx->req)->klass != 2) ) {
DEBUG_WEBDAV("request_dispatch failed with rc=%d", rc );
if( rc == NE_OK ) rc = NE_ERROR;
errno = EACCES;
}
/* delete the hook again, otherwise they get chained as they are with the session */
ne_unhook_post_headers( dav_session.ctx, install_content_reader, writeCtx );
/* if the compression handle is set through the post_header hook, delete it. */
if( writeCtx->decompress ) {
ne_decompress_destroy( writeCtx->decompress );
}
/* delete the request in any case */
ne_request_destroy(writeCtx->req);
#else
DEBUG_WEBDAV("GET Compression not supported!");
rc = ne_get( dav_session.ctx, getUrl, writeCtx->fd ); /* FIX_ESCAPE? */
#endif
if( rc != NE_OK ) {
DEBUG_WEBDAV("Download to local file failed: %d.", rc);
errno = EACCES;
}
if( close( writeCtx->fd ) == -1 ) {
DEBUG_WEBDAV("Close of local download file failed.");
writeCtx->fd = -1;
rc = NE_ERROR;
errno = EACCES;
}
writeCtx->fd = -1;
} }
if( rc != NE_OK ) { if( rc != NE_OK ) {
SAFE_FREE( writeCtx ); SAFE_FREE( writeCtx );
writeCtx = NULL;
} }
SAFE_FREE( dir ); SAFE_FREE( dir );
@ -1128,13 +1121,159 @@ static csync_vio_method_handle_t *owncloud_creat(const char *durl, mode_t mode)
return handle; return handle;
} }
/*
* Puts a file read from the open file descriptor to the ownCloud URL.
*/
static int owncloud_put(csync_vio_method_handle_t *flocal,
csync_vio_method_handle_t *fremote,
csync_vio_file_stat_t *vfs) {
int rc = 0;
int neon_stat;
const ne_status *status;
csync_stat_t sb;
struct transfer_context *write_ctx = (struct transfer_context*) fremote;
int fd;
ne_request *request = NULL;
fd = csync_vio_getfd(flocal);
if (fd == -1) {
errno = EINVAL;
return -1;
}
if( write_ctx == NULL ) {
errno = EINVAL;
return -1;
}
request = write_ctx->req;
if( request == NULL) {
errno = EINVAL;
return -1;
}
/* stat the source-file to get the file size. */
if( fstat( fd, &sb ) == 0 ) {
if( sb.st_size != vfs->size ) {
DEBUG_WEBDAV("WRN: Stat size differs from vfs size!");
}
/* Attach the request to the file descriptor */
ne_set_request_body_fd(request, fd, 0, sb.st_size);
DEBUG_WEBDAV("Put file size: %lld, variable sizeof: %ld", (long long int) sb.st_size,
sizeof(sb.st_size));
/* Start the request. */
neon_stat = ne_request_dispatch( write_ctx->req );
set_errno_from_neon_errcode( neon_stat );
status = ne_get_status( request );
if( status->klass != 2 ) {
DEBUG_WEBDAV("sendfile request failed with http status %d!", status->code);
set_errno_from_http_errcode( status->code );
/* decide if soft error or hard error that stops the whole sync. */
/* Currently all problems concerning one file are soft errors */
if( status->klass == 4 /* Forbidden and stuff, soft error */ ) {
rc = 1;
} else if( status->klass == 5 /* Server errors and such */ ) {
rc = 1; /* No Abort on individual file errors. */
} else {
rc = 1;
}
} else {
DEBUG_WEBDAV("http request all cool, result code %d", status->code);
}
} else {
DEBUG_WEBDAV("Could not stat file descriptor");
rc = 1;
}
return rc;
}
/* Gets a file from the owncloud url to the open file descriptor. */
static int owncloud_get(csync_vio_method_handle_t *flocal,
csync_vio_method_handle_t *fremote,
csync_vio_file_stat_t *vfs) {
int rc = 0;
int neon_stat;
const ne_status *status;
int fd;
struct transfer_context *write_ctx = (struct transfer_context*) fremote;
(void) vfs; /* stat information of the source file */
fd = csync_vio_getfd(flocal);
if (fd == -1) {
errno = EINVAL;
return -1;
}
/* GET a file to the open file descriptor */
if( write_ctx == NULL ) {
errno = EINVAL;
return -1;
}
if( write_ctx->req == NULL ) {
errno = EINVAL;
return -1;
}
DEBUG_WEBDAV(" -- GET on %s", write_ctx->url);
write_ctx->fd = fd;
/* Allow compressed content by setting the header */
ne_add_request_header( write_ctx->req, "Accept-Encoding", "gzip,deflate" );
/* hook called before the content is parsed to set the correct reader,
* either the compressed- or uncompressed reader.
*/
ne_hook_post_headers( dav_session.ctx, install_content_reader, write_ctx );
neon_stat = ne_request_dispatch(write_ctx->req );
/* possible return codes are:
* NE_OK, NE_AUTH, NE_CONNECT, NE_TIMEOUT, NE_ERROR (from ne_request.h)
*/
if( neon_stat != NE_OK ) {
set_errno_from_neon_errcode(neon_stat);
DEBUG_WEBDAV("Error GET: Neon: %d, errno %d", neon_stat, errno);
rc = -1;
} else {
status = ne_get_status( write_ctx->req );
if( status->klass != 2 ) {
DEBUG_WEBDAV("sendfile request failed with http status %d!", status->code);
set_errno_from_http_errcode( status->code );
/* decide if soft error or hard error that stops the whole sync. */
/* Currently all problems concerning one file are soft errors */
if( status->klass == 4 /* Forbidden and stuff, soft error */ ) {
rc = 1;
} else if( status->klass == 5 /* Server errors and such */ ) {
rc = 1; /* No Abort on individual file errors. */
} else {
rc = 1;
}
} else {
DEBUG_WEBDAV("http request all cool, result code %d (%s)", status->code,
status->reason_phrase ? status->reason_phrase : "<empty>");
}
}
/* delete the hook again, otherwise they get chained as they are with the session */
ne_unhook_post_headers( dav_session.ctx, install_content_reader, write_ctx );
/* if the compression handle is set through the post_header hook, delete it. */
if( write_ctx->decompress ) {
ne_decompress_destroy( write_ctx->decompress );
}
return rc;
}
static int owncloud_close(csync_vio_method_handle_t *fhandle) { static int owncloud_close(csync_vio_method_handle_t *fhandle) {
struct transfer_context *writeCtx; struct transfer_context *writeCtx;
csync_stat_t st;
int rc;
int ret = 0; int ret = 0;
size_t len = 0;
mbchar_t *tmpFileName = 0;
enum csync_notify_type_e notify_tag; enum csync_notify_type_e notify_tag;
writeCtx = (struct transfer_context*) fhandle; writeCtx = (struct transfer_context*) fhandle;
@ -1144,103 +1283,13 @@ static int owncloud_close(csync_vio_method_handle_t *fhandle) {
ret = -1; ret = -1;
} }
/* handle the PUT request, means write to the WebDAV server */ /* handle the PUT request */
if( ret != -1 && strcmp( writeCtx->method, "PUT" ) == 0 ) { if( ret != -1 && strcmp( writeCtx->method, "PUT" ) == 0 ) {
notify_tag = CSYNC_NOTIFY_FINISHED_UPLOAD;
/* if there is a valid file descriptor, close it, reopen in read mode and start the PUT request */ ne_request_destroy( writeCtx->req );
if( writeCtx->fd > -1 ) {
if( writeCtx->fileWritten && writeCtx->bytes_written > 0 ) { /* was content written to file? */
/* push the rest of the buffer to file as well. */
DEBUG_WEBDAV("Write remaining %lu bytes to disk.",
(unsigned long) writeCtx->bytes_written);
len = write( writeCtx->fd, _buffer, writeCtx->bytes_written );
if( len != writeCtx->bytes_written ) {
DEBUG_WEBDAV("WRN: write wrote wrong number of remaining bytes");
}
writeCtx->bytes_written = 0;
}
if( close( writeCtx->fd ) < 0 ) {
DEBUG_WEBDAV("Could not close file %s", writeCtx->tmpFileName );
errno = EBADF;
ret = -1;
}
/* and open it again to read from */
#ifdef _WIN32
_fmode = _O_BINARY;
#endif
if( writeCtx->fileWritten ) {
DEBUG_WEBDAV("Putting file through file cache.");
/* we need to go the slow way and close and open the file and read from fd. */
tmpFileName = c_utf8_to_locale( writeCtx->tmpFileName );
if (( writeCtx->fd = _topen( tmpFileName, O_RDONLY )) < 0) {
errno = EIO;
ret = -1;
} else {
if (fstat( writeCtx->fd, &st ) < 0) {
DEBUG_WEBDAV("Could not stat file %s", writeCtx->tmpFileName );
errno = EIO;
ret = -1;
}
/* successfully opened for read. Now start the request via ne_put */
ne_set_request_body_fd( writeCtx->req, writeCtx->fd, 0, st.st_size );
if (_file_progress_cb) {
ne_set_notifier(dav_session.ctx, ne_notify_status_cb, writeCtx);
_file_progress_cb(writeCtx->url, CSYNC_NOTIFY_START_UPLOAD, 0 , 0, _userdata);
}
rc = ne_request_dispatch( writeCtx->req );
if( close( writeCtx->fd ) == -1 ) {
errno = EBADF;
ret = -1;
}
if (rc == NE_OK) {
if ( ne_get_status( writeCtx->req )->klass != 2 ) {
DEBUG_WEBDAV("Error - PUT status value no 2xx");
errno = EIO;
ret = -1;
}
} else {
DEBUG_WEBDAV("Error - put request on close failed: %d!", rc );
errno = EIO;
ret = -1;
}
}
c_free_locale_string(tmpFileName);
} else {
/* all content is in the buffer. */
DEBUG_WEBDAV("Putting file through memory cache.");
ne_set_request_body_buffer( writeCtx->req, _buffer, writeCtx->bytes_written );
rc = ne_request_dispatch( writeCtx->req );
if( rc == NE_OK ) {
if ( ne_get_status( writeCtx->req )->klass != 2 ) {
DEBUG_WEBDAV("Error - PUT status value no 2xx");
errno = EIO;
ret = -1;
}
} else {
DEBUG_WEBDAV("Error - put request from memory failed: %d!", rc );
errno = EIO;
ret = -1;
}
}
notify_tag = CSYNC_NOTIFY_FINISHED_UPLOAD;
}
ne_request_destroy( writeCtx->req );
} else { } else {
/* Its a GET request, not much to do in close. */ /* Its a GET request. */
if( writeCtx->fd > -1) { notify_tag = CSYNC_NOTIFY_FINISHED_DOWNLOAD;
if( close( writeCtx->fd ) == -1 ) {
errno = EBADF;
ret = -1;
}
}
notify_tag = CSYNC_NOTIFY_FINISHED_DOWNLOAD;
} }
/* Finish callback */ /* Finish callback */
@ -1249,11 +1298,7 @@ static int owncloud_close(csync_vio_method_handle_t *fhandle) {
_file_progress_cb(writeCtx->url, notify_tag, 0, 0, _userdata ); _file_progress_cb(writeCtx->url, notify_tag, 0, 0, _userdata );
} }
/* Remove the local file. */
unlink( writeCtx->tmpFileName );
/* free mem. Note that the request mem is freed by the ne_request_destroy call */ /* free mem. Note that the request mem is freed by the ne_request_destroy call */
SAFE_FREE( writeCtx->tmpFileName );
SAFE_FREE( writeCtx->url ); SAFE_FREE( writeCtx->url );
SAFE_FREE( writeCtx ); SAFE_FREE( writeCtx );
@ -1261,49 +1306,13 @@ static int owncloud_close(csync_vio_method_handle_t *fhandle) {
} }
static ssize_t owncloud_read(csync_vio_method_handle_t *fhandle, void *buf, size_t count) { static ssize_t owncloud_read(csync_vio_method_handle_t *fhandle, void *buf, size_t count) {
struct transfer_context *writeCtx;
size_t len = 0;
csync_stat_t st;
mbchar_t *tmpFileName;
writeCtx = (struct transfer_context*) fhandle; (void) fhandle;
(void) buf;
(void) count;
DEBUG_WEBDAV("XXXXXXXXXXXXXXXXXXX We should not have come here - owncloud_read");
if( ! fhandle ) { return 0;
errno = EBADF;
return -1;
}
if( writeCtx->fd == -1 ) {
/* open the downloaded file to read from */
#ifdef _WIN32
_fmode = _O_BINARY;
#endif
tmpFileName = c_utf8_to_locale(writeCtx->tmpFileName);
if (( writeCtx->fd = _topen( tmpFileName, O_RDONLY )) < 0) {
c_free_locale_string(tmpFileName);
DEBUG_WEBDAV("Could not open local file %s", writeCtx->tmpFileName );
errno = EIO;
return -1;
} else {
c_free_locale_string(tmpFileName);
if (fstat( writeCtx->fd, &st ) < 0) {
DEBUG_WEBDAV("Could not stat file %s", writeCtx->tmpFileName );
errno = EIO;
return -1;
}
DEBUG_WEBDAV("local downlaod file size=%d", (int) st.st_size );
}
}
if( writeCtx->fd ) {
len = read( writeCtx->fd, buf, count );
writeCtx->bytes_written = writeCtx->bytes_written + len;
}
/* DEBUG_WEBDAV( "read len: %d %ul, len, count ); */
return len;
} }
static off_t owncloud_lseek(csync_vio_method_handle_t *fhandle, off_t offset, int whence) { static off_t owncloud_lseek(csync_vio_method_handle_t *fhandle, off_t offset, int whence) {
@ -1615,7 +1624,9 @@ csync_vio_method_t _method = {
.chown = owncloud_chown, .chown = owncloud_chown,
.utimes = owncloud_utimes, .utimes = owncloud_utimes,
.get_error_string = owncloud_error_string, .get_error_string = owncloud_error_string,
.set_property = owncloud_set_property .set_property = owncloud_set_property,
.put = owncloud_put,
.get = owncloud_get
}; };
csync_vio_method_t *vio_module_init(const char *method_name, const char *args, csync_vio_method_t *vio_module_init(const char *method_name, const char *args,