/* 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) { struct transfer_context *writeCtx; int rc = 0; int neon_stat; const ne_status *status; writeCtx = (struct transfer_context*) fhandle; if (fhandle == NULL) { errno = EBADF; rc = -1; } ne_set_request_body_buffer(writeCtx->req, buf, count ); /* Start the request. */ neon_stat = ne_request_dispatch( writeCtx->req ); set_errno_from_neon_errcode( neon_stat ); status = ne_get_status( writeCtx->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("write request all ok, result code %d", status->code); } return rc; }
static int fetch_resource_list( const char *uri, int depth, struct listdir_context *fetchCtx ) { 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; curi = _cleanPath( uri ); if (!fetchCtx) { errno = ENOMEM; SAFE_FREE(curi); return -1; } fetchCtx->list = NULL; fetchCtx->target = curi; fetchCtx->currResource = NULL; /* do a propfind request and parse the results in the results function, set as callback */ hdl = ne_propfind_create(dav_session.ctx, curi, depth); 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); } DEBUG_WEBDAV("Simple propfind result code %d.", req_status ? req_status->code : -1); } else { if( ret == NE_ERROR && req_status->code == 404) { errno = ENOENT; } else { set_errno_from_neon_errcode(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") ) ) { 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!"); ret = NE_CONNECT; } } #ifndef NDEBUG if( ret != NE_OK ) { const char *err = ne_get_error(dav_session.ctx); DEBUG_WEBDAV("WRN: propfind named failed with %d, request error: %s", ret, err ? err : "<nil>"); } #endif /* NDEBUG */ if (hdl != NULL) { ne_propfind_destroy(hdl); } #ifndef NDEBUG if (ret == NE_REDIRECT) { const ne_uri *redir_ne_uri = ne_redirect_location(dav_session.ctx); if (redir_ne_uri) { char *redir_uri = ne_uri_unparse(redir_ne_uri); DEBUG_WEBDAV("Permanently moved to %s", redir_uri); } } #endif /* NDEBUG */ if( ret != NE_OK ) { free_fetchCtx(fetchCtx); return -1; } return 0; }
/* 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; }
/* * 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; }
void fetch_resource_list_recursive(const char *uri, const char *curi) { int ret = 0; ne_propfind_handler *hdl = NULL; ne_request *request = NULL; const char *content_type = NULL; const ne_status *req_status = NULL; int depth = NE_DEPTH_INFINITE; DEBUG_WEBDAV("fetch_resource_list_recursive Starting recursive propfind %s %s", uri, curi); /* do a propfind request and parse the results in the results function, set as callback */ hdl = ne_propfind_create(dav_session.ctx, curi, depth); if(hdl) { ret = ne_propfind_named(hdl, ls_props, propfind_results_recursive, (void*)curi); request = ne_propfind_get_request( hdl ); req_status = ne_get_status( request ); } if( ret == NE_OK ) { /* 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); } DEBUG_WEBDAV("Recursive propfind result code %d.", req_status ? req_status->code : 0); } else { if( ret == NE_ERROR && req_status->code == 404) { errno = ENOENT; } else { set_errno_from_neon_errcode(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") ) ) { 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!"); 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_OK ) { return; } return; }
/* * 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) { struct listdir_context *fetchCtx; 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; curi = _cleanPath( uri ); /* The old legacy one-level PROPFIND cache. Also gets filled by the recursive cache if 'infinity' did not suceed. */ if (propfind_cache) { if (c_streq(curi, propfind_cache->target)) { DEBUG_WEBDAV("fetch_resource_list Using simple PROPFIND cache %s", curi); propfind_cache->ref++; SAFE_FREE(curi); return propfind_cache; } } fetchCtx = c_malloc( sizeof( struct listdir_context )); if (!fetchCtx) { errno = ENOMEM; SAFE_FREE(curi); return NULL; } fetchCtx->list = NULL; fetchCtx->target = curi; fetchCtx->currResource = NULL; fetchCtx->ref = 1; /* do a propfind request and parse the results in the results function, set as callback */ hdl = ne_propfind_create(dav_session.ctx, curi, depth); 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); oc_notify_progress( uri, CSYNC_NOTIFY_ERROR, req_status->code, (intptr_t)(req_status->reason_phrase) ); } 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") ) ) { 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!"); ret = NE_CONNECT; } } if( ret != NE_OK ) { const char *err = NULL; set_errno_from_neon_errcode(ret); err = ne_get_error( dav_session.ctx ); if(err) { set_error_message(err); } DEBUG_WEBDAV("WRN: propfind named failed with %d, request error: %s", ret, err ? err : "<nil>"); } if( hdl ) ne_propfind_destroy(hdl); if( ret != NE_OK ) { free_fetchCtx(fetchCtx); return NULL; } free_fetchCtx(propfind_cache); propfind_cache = fetchCtx; propfind_cache->ref++; return fetchCtx; }
static const char* owncloud_get_etag( const char *path ) { ne_request *req = NULL; const char *header = NULL; char *uri = _cleanPath(path); char *cbuf = NULL; csync_vio_file_stat_t *fs = NULL; bool doHeadRequest = false; if (_id_cache.uri && c_streq(path, _id_cache.uri)) { header = _id_cache.id; } doHeadRequest= false; /* ownCloud server doesn't have good support for HEAD yet */ if( !header && doHeadRequest ) { int neon_stat; /* Perform an HEAD request to the resource. HEAD delivers the * ETag header back. */ req = ne_request_create(dav_session.ctx, "HEAD", uri); neon_stat = ne_request_dispatch(req); set_errno_from_neon_errcode( neon_stat ); header = ne_get_response_header(req, "etag"); } /* If the request went wrong or the server did not respond correctly * (that can happen for collections) a stat call is done which translates * into a PROPFIND request. */ if( ! header ) { /* ... and do a stat call. */ fs = csync_vio_file_stat_new(); if(fs == NULL) { DEBUG_WEBDAV( "owncloud_get_etag: memory fault."); errno = ENOMEM; return NULL; } if( owncloud_stat( path, fs ) == 0 ) { header = fs->etag; } } /* In case the result is surrounded by "" cut them away. */ if( header ) { cbuf = csync_normalize_etag(header); } /* fix server problem: If we end up with an empty string, set something strange... */ if( c_streq(cbuf, "") || c_streq(cbuf, "\"\"") ) { SAFE_FREE(cbuf); cbuf = c_strdup("empty_etag"); } DEBUG_WEBDAV("Get file ID for %s: %s", path, cbuf ? cbuf:"<null>"); if( fs ) csync_vio_file_stat_destroy(fs); if( req ) ne_request_destroy(req); SAFE_FREE(uri); return cbuf; }