From 141a095d45cb3db48d694abb27da360975746a4a Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Tue, 13 Sep 2011 14:15:44 +0200 Subject: [PATCH] module: Start with some webdav code based on libneon. --- modules/csync_webdav.c | 325 +++++++++++++++++++++++++++++++++++------ 1 file changed, 282 insertions(+), 43 deletions(-) diff --git a/modules/csync_webdav.c b/modules/csync_webdav.c index f4fd9550e9..6ed46ca47b 100644 --- a/modules/csync_webdav.c +++ b/modules/csync_webdav.c @@ -1,7 +1,7 @@ /* * libcsync -- a library to sync a directory with another * - * Copyright (c) 2008 by Andreas Schneider + * Copyright (c) 2011 by Andreas Schneider * * This program is free software = NULL, you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -21,20 +21,26 @@ #include #include #include +#include +#include +#include + +#include #include #include +#include #include "c_lib.h" #include "vio/csync_vio_module.h" #include "vio/csync_vio_file_stat.h" #ifdef NDEBUG -#define DEBUG_DUMMY(x) +#define DEBUG_WEBDAV(x) #else -#define DEBUG_DUMMY(x) printf x +#define DEBUG_WEBDAV(x) printf x #endif -struct dav_session { +struct dav_session_s { ne_session *ctx; char *base_uri; char *user; @@ -46,7 +52,104 @@ int _connected; csync_vio_file_stat_t fs; -static int _dav_connect(const char *base_url) { +static int ne_session_error_errno(ne_session *session) +{ + const char *p = ne_get_error(session); + char *q; + int err; + + err = strtol(p, &q, 10); + if (p == q) { + return EIO; + } + + switch(err) { + case 200: /* OK */ + case 201: /* Created */ + case 202: /* Accepted */ + case 203: /* Non-Authoritative Information */ + case 204: /* No Content */ + case 205: /* Reset Content */ + case 207: /* Multi-Status */ + case 304: /* Not Modified */ + return 0; + case 401: /* Unauthorized */ + case 402: /* Payment Required */ + case 407: /* Proxy Authentication Required */ + return EPERM; + case 301: /* Moved Permanently */ + case 303: /* See Other */ + case 404: /* Not Found */ + case 410: /* Gone */ + return ENOENT; + case 408: /* Request Timeout */ + case 504: /* Gateway Timeout */ + return EAGAIN; + case 423: /* Locked */ + return EACCES; + case 400: /* Bad Request */ + case 403: /* Forbidden */ + case 405: /* Method Not Allowed */ + case 409: /* Conflict */ + case 411: /* Length Required */ + case 412: /* Precondition Failed */ + case 414: /* Request-URI Too Long */ + case 415: /* Unsupported Media Type */ + case 424: /* Failed Dependency */ + case 501: /* Not Implemented */ + return EINVAL; + case 413: /* Request Entity Too Large */ + case 507: /* Insufficient Storage */ + return ENOSPC; + case 206: /* Partial Content */ + case 300: /* Multiple Choices */ + case 302: /* Found */ + case 305: /* Use Proxy */ + case 306: /* (Unused) */ + case 307: /* Temporary Redirect */ + case 406: /* Not Acceptable */ + case 416: /* Requested Range Not Satisfiable */ + case 417: /* Expectation Failed */ + case 422: /* Unprocessable Entity */ + case 500: /* Internal Server Error */ + case 502: /* Bad Gateway */ + case 503: /* Service Unavailable */ + case 505: /* HTTP Version Not Supported */ + return EIO; + default: + return EIO; + } + + return EIO; +} + +static int ne_error_to_errno(int ne_err) +{ + switch (ne_err) { + case NE_OK: + case NE_ERROR: + return 0; + case NE_AUTH: + case NE_PROXYAUTH: + return EACCES; + case NE_CONNECT: + case NE_TIMEOUT: + case NE_RETRY: + return EAGAIN; + case NE_FAILED: + return EINVAL; + case NE_REDIRECT: + return ENOENT; + case NE_LOOKUP: + return EIO; + default: + return EIO; + } + + return EIO; +} + +static int ne_dav_connect(const char *base_url) { char *scheme = NULL; char *user = NULL; char *passwd = NULL; @@ -61,7 +164,7 @@ static int _dav_connect(const char *base_url) { return 0; } - rc = c_parse_uri(uri, &scheme, &user, &passwd, &host, &port, &path); + rc = c_parse_uri(base_url, &scheme, &user, &passwd, &host, &port, &path); if (rc < 0) { goto out; } @@ -72,7 +175,7 @@ static int _dav_connect(const char *base_url) { } if (uri.scheme == NULL) { - uri.scheme = "http"; + uri.scheme = c_strdup("http"); } if (uri.port == 0) { @@ -85,13 +188,13 @@ static int _dav_connect(const char *base_url) { } dav_session.ctx = ne_session_create(uri.scheme, uri.host, uri.port); - if (dav_session == NULL) { + if (dav_session.ctx == NULL) { return -1; } ne_set_read_timeout(dav_session.ctx, timeout); - ne_set_server_auth(); + /* ne_set_server_auth(); */ _connected = 1; rc = 0; @@ -101,7 +204,6 @@ out: SAFE_FREE(passwd); SAFE_FREE(host); SAFE_FREE(path); - SAFE_FREE(hash); return rc; } @@ -110,46 +212,101 @@ out: * file functions */ -static csync_vio_method_handle_t *_open(const char *durl, int flags, mode_t mode) { - csync_vio_method_handle_t *mh = NULL; +static csync_vio_method_handle_t *_open(const char *durl, + int flags, + mode_t mode) { + char *uri; + ne_request *req; + int put = 0; - (void) durl; - (void) flags; - (void) mode; + (void) mode; /* unused */ - return mh; + uri = ne_path_escape(durl); + if (uri == NULL) { + return NULL; + } + + if (flags & O_WRONLY) { + put = 1; + } + if (flags & O_RDWR) { + put = 1; + } + if (flags & O_CREAT) { + put = 1; + } + + /* FIXME */ + if (put) { + req = ne_request_create(dav_session.ctx, "PUT", uri); + } else { + req = ne_request_create(dav_session.ctx, "GET", uri); + } + + return (csync_vio_method_handle_t *) req; } static csync_vio_method_handle_t *_creat(const char *durl, mode_t mode) { - (void) durl; - (void) mode; - - return &mh; + return _open(durl, O_CREAT|O_WRONLY|O_TRUNC, mode); } static int _close(csync_vio_method_handle_t *fhandle) { - (void) fhandle; + ne_request *req; + + if (fhandle == NULL) { + return -1; + } + req = (ne_request *)fhandle; + + ne_request_destroy(req); return 0; } static ssize_t _read(csync_vio_method_handle_t *fhandle, void *buf, size_t count) { - (void) fhandle; - (void) buf; - (void) count; + ne_request *req = (ne_request *)fhandle; + const ne_status *const st = ne_get_status(req); + ssize_t len; + int rc; - /* GET request */ - return 0; + rc = ne_begin_request(req); + if (rc != NE_OK) { + return -1; + } + + do { + if (st->klass == 2) { + rc = NE_OK; + len = ne_read_response_block(req, buf, count); + if (len < 0) { + rc = NE_ERROR; + } + } else { + rc = ne_discard_response(req); + len = -1; + } + } while(rc == NE_RETRY); + + if (rc == NE_OK) { + rc = ne_end_request(req); + } + + return len; } static ssize_t _write(csync_vio_method_handle_t *fhandle, const void *buf, size_t count) { - (void) fhandle; - (void) buf; - (void) count; + ne_request *req = (ne_request *)fhandle; + ssize_t len = count; + int rc; - /* put request */ + ne_set_request_body_buffer(req, buf, count); - return 0; + rc = ne_request_dispatch(req); + if (rc == NE_OK && ne_get_status(req)->klass != 2) { + len = -1; + } + + return len; } static off_t _lseek(csync_vio_method_handle_t *fhandle, off_t offset, int whence) { @@ -157,7 +314,7 @@ static off_t _lseek(csync_vio_method_handle_t *fhandle, off_t offset, int whence (void) offset; (void) whence; - return 0; + return -1; } /* @@ -167,7 +324,7 @@ static off_t _lseek(csync_vio_method_handle_t *fhandle, off_t offset, int whence static csync_vio_method_handle_t *_opendir(const char *name) { (void) name; - return &mh; + return NULL; } static int _closedir(csync_vio_method_handle_t *dhandle) { @@ -183,14 +340,51 @@ static csync_vio_file_stat_t *_readdir(csync_vio_method_handle_t *dhandle) { } static int _mkdir(const char *uri, mode_t mode) { - (void) uri; - (void) mode; + char *suri; + int rc; + + (void) mode; /* unused */ + + suri = ne_path_escape(uri); + if (suri == NULL) { + return -1; + } + + rc = ne_dav_connect(suri); + if (rc < 0) { + errno = EINVAL; + return -1; + } + + rc = ne_mkcol(dav_session.ctx, suri); + if (rc != 0) { + errno = ne_error_to_errno(rc); + return -1; + } return 0; } static int _rmdir(const char *uri) { - (void) uri; + char *suri; + int rc; + + suri = ne_path_escape(uri); + if (suri == NULL) { + return -1; + } + + rc = ne_dav_connect(suri); + if (rc < 0) { + errno = EINVAL; + return -1; + } + + rc = ne_delete(dav_session.ctx, uri); + if (rc != 0) { + errno = ne_error_to_errno(rc); + return -1; + } return 0; } @@ -198,6 +392,12 @@ static int _rmdir(const char *uri) { static int _stat(const char *uri, csync_vio_file_stat_t *buf) { time_t now; + /* get props: + * modtime + * creattime + * size + */ + buf->name = c_basename(uri); if (buf->name == NULL) { csync_vio_file_stat_destroy(buf); @@ -212,14 +412,55 @@ static int _stat(const char *uri, csync_vio_file_stat_t *buf) { } static int _rename(const char *olduri, const char *newuri) { - (void) olduri; - (void) newuri; + char *ouri; + char *nuri; + int rc; + + ouri = ne_path_escape(olduri); + if (ouri == NULL) { + return -1; + } + + nuri = ne_path_escape(newuri); + if (nuri == NULL) { + return -1; + } + + rc = ne_dav_connect(ouri); + if (rc < 0) { + errno = EINVAL; + return -1; + } + + rc = ne_move(dav_session.ctx, 1, ouri, nuri); + if (rc != 0) { + errno = ne_error_to_errno(rc); + return -1; + } return 0; } static int _unlink(const char *uri) { - (void) uri; + char *suri; + int rc; + + suri = ne_path_escape(uri); + if (suri == NULL) { + return -1; + } + + rc = ne_dav_connect(suri); + if (rc < 0) { + errno = EINVAL; + return -1; + } + + rc = ne_delete(dav_session.ctx, uri); + if (rc != 0) { + errno = ne_error_to_errno(rc); + return -1; + } return 0; } @@ -269,16 +510,14 @@ csync_vio_method_t _method = { csync_vio_method_t *vio_module_init(const char *method_name, const char *args, csync_auth_callback cb, void *userdata) { - DEBUG_DUMMY(("csync_dummy - method_name: %s\n", method_name)); - DEBUG_DUMMY(("csync_dummy - args: %s\n", args)); + DEBUG_WEBDAV(("csync_webdav - method_name: %s\n", method_name)); + DEBUG_WEBDAV(("csync_webdav - args: %s\n", args)); (void) method_name; (void) args; (void) cb; (void) userdata; - mh = (void *) method_name; - fs.mtime = 42; return &_method; }