Fri, 24 Jul 2020 08:00:11 +0200
prepare webdav copy
--- a/src/server/public/webdav.h Sat Jul 11 17:58:00 2020 +0200 +++ b/src/server/public/webdav.h Fri Jul 24 08:00:11 2020 +0200 @@ -173,6 +173,7 @@ WSBool allprop; WSBool propname; + WSBool deadproperties; int depth;
--- a/src/server/webdav/multistatus.c Sat Jul 11 17:58:00 2020 +0200 +++ b/src/server/webdav/multistatus.c Fri Jul 24 08:00:11 2020 +0200 @@ -559,9 +559,14 @@ if(response->closing) { return 0; // close already in progress } + response->closing = TRUE; Multistatus *ms = response->multistatus; int ret = REQ_PROCEED; + + // PROPFIND: + // response_close will execute propfind_do of all remaining backends + // after that we will have all available properties WebdavOperation *op = ms->response.op; if(op->response_close(op, res)) { ret = REQ_ABORTED; @@ -617,6 +622,5 @@ ucx_map_free(response->properties); response->resource.isclosed = TRUE; - response->closing = FALSE; return ret; }
--- a/src/server/webdav/operation.h Sat Jul 11 17:58:00 2020 +0200 +++ b/src/server/webdav/operation.h Fri Jul 24 08:00:11 2020 +0200 @@ -30,6 +30,8 @@ #define OPERATION_H #include "../public/webdav.h" +#include <ucx/list.h> +#include <ucx/map.h> #ifdef __cplusplus extern "C" { @@ -38,6 +40,9 @@ typedef int(*response_close_func)(WebdavOperation *, WebdavResource *); typedef struct WebdavVFSOperation WebdavVFSOperation; + +typedef struct WebdavCopy WebdavCopy; +typedef struct CopyResource CopyResource; struct WebdavOperation { WebdavBackend *dav; @@ -68,6 +73,23 @@ int stat_errno; }; +struct WebdavCopy { + WebdavResponse response; + Session *sn; + Request *rq; + CopyResource *current; + + char *src_href; + char *src_path; + char *dst_href; + char *dst_path; +}; + +struct CopyResource { + WebdavResource resource; + UcxMap *properties; +}; + enum WebdavVFSOpType { WEBDAV_VFS_MKDIR = 0, WEBDAV_VFS_DELETE @@ -159,6 +181,16 @@ int webdav_vfs_unlink(WebdavVFSOperation *op); + +WebdavCopy* webdav_copy_create( + Session *sn, + Request *rq, + VFSContext *vfs, + char *from_href, + char *from_path, + char *to_href, + char *to_path); + #ifdef __cplusplus } #endif
--- a/src/server/webdav/webdav.c Sat Jul 11 17:58:00 2020 +0200 +++ b/src/server/webdav/webdav.c Fri Jul 24 08:00:11 2020 +0200 @@ -208,17 +208,6 @@ char *path = pblock_findkeyval(pb_key_path, rq->vars); char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb); - // VFS settings are only taken from the first backend - uint32_t settings = dav->settings; - - // list of individual WebdavPropfindRequest objects for each Backend - UcxList *requestObjects = NULL; - - // Initialize all Webdav Backends - if(webdav_propfind_init(dav, propfind, path, &requestObjects)) { - return REQ_ABORTED; - } - // The multistatus response object contains responses for all // requested resources. At the end the Multistatus object will be // serialized to xml @@ -226,63 +215,9 @@ if(!ms) { return REQ_ABORTED; } - // WebdavResponse is the public interface used by Backends - // for adding resources to the response - WebdavResponse *response = (WebdavResponse*)ms; - WebdavOperation *op = webdav_create_propfind_operation( - sn, - rq, - dav, - propfind->properties, - requestObjects, - response); - - // some Backends can list all children by themselves, but some - // require the VFS for this - WSBool usevfs = (settings & WS_WEBDAV_PROPFIND_USE_VFS) - == WS_WEBDAV_PROPFIND_USE_VFS; - struct stat s; - struct stat *statptr = NULL; - VFSContext *vfs = NULL; - if(usevfs) { - vfs = vfs_request_context(sn, rq); - if(!vfs) { - return REQ_ABORTED; - } - - if(vfs_stat(vfs, path, &s)) { - protocol_status(sn, rq, util_errno2status(vfs->vfs_errno), NULL); - return REQ_ABORTED; - } - statptr = &s; - if(!S_ISDIR(s.st_mode)) { - // the file is not a directory, therefore we don't need the VFS - usevfs = FALSE; - } - } - if(propfind->depth == 0) { - usevfs = FALSE; - } - - int ret = REQ_PROCEED; - - // create WebdavResource object for requested resource - if(!webdav_op_propfind_begin(op, uri, NULL, statptr)) { - // propfind for the requested resource was successful - - // usevfsdir is TRUE if - // the webdav backend has not disabled vfs usage - // the file is a directory - // depth is not 0 - // in this case we need to execute propfind_do for all children - if(usevfs) { - if(webdav_op_propfind_children(op, vfs, uri, path)) { - ret = REQ_ABORTED; - } - } - } + int ret = webdav_propfind_do(dav, propfind, (WebdavResponse*)ms, NULL, path, uri); // if propfind was successful, send the result to the client if(ret == REQ_PROCEED && multistatus_send(ms, sn->csd)) { @@ -292,17 +227,11 @@ // TODO: error response } - // finish the propfind request - // this function should cleanup all resources, therefore we execute it - // even if a previous function failed - if(webdav_op_propfind_finish(op)) { - // TODO: log error - ret = REQ_ABORTED; + // cleanup + if(propfind->doc) { + xmlFreeDoc(propfind->doc); } - // cleanup - xmlFreeDoc(propfind->doc); - return ret; } @@ -367,6 +296,92 @@ return REQ_PROCEED; } +int webdav_propfind_do( + WebdavBackend *dav, + WebdavPropfindRequest *propfind, + WebdavResponse *response, + VFSContext *vfs, + char *path, + char *uri) +{ + Session *sn = propfind->sn; + Request *rq = propfind->rq; + + // VFS settings are only taken from the first backend + uint32_t settings = dav->settings; + + // list of individual WebdavPropfindRequest objects for each Backend + UcxList *requestObjects = NULL; + + // Initialize all Webdav Backends + if(webdav_propfind_init(dav, propfind, path, &requestObjects)) { + return REQ_ABORTED; + } + + WebdavOperation *op = webdav_create_propfind_operation( + sn, + rq, + dav, + propfind->properties, + requestObjects, + response); + + // some Backends can list all children by themselves, but some + // require the VFS for this + WSBool usevfs = (settings & WS_WEBDAV_PROPFIND_USE_VFS) + == WS_WEBDAV_PROPFIND_USE_VFS; + struct stat s; + struct stat *statptr = NULL; + + if(usevfs && !vfs) { + vfs = vfs_request_context(sn, rq); + if(!vfs) { + return REQ_ABORTED; + } + + if(vfs_stat(vfs, path, &s)) { + protocol_status(sn, rq, util_errno2status(vfs->vfs_errno), NULL); + return REQ_ABORTED; + } + statptr = &s; + if(!S_ISDIR(s.st_mode)) { + // the file is not a directory, therefore we don't need the VFS + usevfs = FALSE; + } + } + if(propfind->depth == 0) { + usevfs = FALSE; + } + + int ret = REQ_PROCEED; + + // create WebdavResource object for requested resource + if(!webdav_op_propfind_begin(op, uri, NULL, statptr)) { + // propfind for the requested resource was successful + + // usevfsdir is TRUE if + // the webdav backend has not disabled vfs usage + // the file is a directory + // depth is not 0 + // in this case we need to execute propfind_do for all children + if(usevfs) { + if(webdav_op_propfind_children(op, vfs, uri, path)) { + ret = REQ_ABORTED; + } + } + } + + // finish the propfind request + // this function should cleanup all resources, therefore we execute it + // even if a previous function failed + if(webdav_op_propfind_finish(op)) { + // TODO: log error + ret = REQ_ABORTED; + } + + return ret; +} + int webdav_proppatch(pblock *pb, Session *sn, Request *rq) { char *expect = pblock_findkeyval(pb_key_expect, rq->headers); @@ -662,6 +677,30 @@ } int webdav_copy(pblock *pb, Session *sn, Request *rq) { + char *path = pblock_findkeyval(pb_key_path, rq->vars); + char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb); + + char *destination = pblock_findval("destination", rq->headers); + if(!destination) { + protocol_status(sn, rq, PROTOCOL_BAD_REQUEST, NULL); + return REQ_ABORTED; + } + + VFSContext *vfs = vfs_request_context(sn, rq); + if(!vfs) { + protocol_status(sn, rq, PROTOCOL_SERVER_ERROR, NULL); + return REQ_ABORTED; + } + + struct stat src_s; + if(vfs_stat(vfs, path, &src_s)) { + protocol_status(sn, rq, util_errno2status(vfs->vfs_errno), NULL); + return REQ_ABORTED; + } + + // TODO: if src is a directory, make sure the uri has a trailing path separator + + return REQ_ABORTED; }
--- a/src/server/webdav/webdav.h Sat Jul 11 17:58:00 2020 +0200 +++ b/src/server/webdav/webdav.h Fri Jul 24 08:00:11 2020 +0200 @@ -68,6 +68,14 @@ const char *path, UcxList **out_req); +int webdav_propfind_do( + WebdavBackend *dav, + WebdavPropfindRequest *propfind, + WebdavResponse *response, + VFSContext *vfs, + char *path, + char *uri); + int webdav_proppatch(pblock *pb, Session *sn, Request *rq); int webdav_mkcol(pblock *pb, Session *sn, Request *rq);