src/server/webdav/operation.c

branch
webdav
changeset 241
4adad7faf452
parent 239
d5031c30022c
child 245
a193c42fc809
--- a/src/server/webdav/operation.c	Sat Jan 25 15:34:30 2020 +0100
+++ b/src/server/webdav/operation.c	Sat Jan 25 21:37:38 2020 +0100
@@ -37,6 +37,16 @@
 
 #define WEBDAV_PATH_MAX 8192
 
+
+size_t webdav_num_backends(WebdavBackend *dav) {
+    size_t count = 0;
+    while(dav) {
+        count++;
+        dav = dav->next;
+    }
+    return count;
+}
+
 /****************************************************************************
  * 
  *                         PROPFIND OPERATION
@@ -367,16 +377,149 @@
     op->rq = rq;
     op->reqprops = NULL;
     op->response = response;
+    op->proppatch = proppatch;
     op->response_close = webdav_op_proppatch_close_resource;
     response->op = op;
     
     return op;
 }
 
+
+
+int webdav_op_proppatch(
+        WebdavOperation *op,
+        const char *href,
+        const char *path)
+{
+    WebdavProppatchRequest *orig_request = op->proppatch;
+    UcxAllocator *a = session_get_allocator(op->sn);
+    
+    // create WebdavResource object for the requested resource
+    WebdavResource *resource = op->response->addresource(op->response, href);
+    if(!resource) {
+        return REQ_ABORTED;
+    }
+    
+    VFSContext *ctx = NULL;
+    VFSFile *file = NULL;
+    
+    // requests for each backends
+    WebdavProppatchRequest **requests = pool_calloc(
+            op->sn->pool,
+            webdav_num_backends(op->dav),
+            sizeof(WebdavProppatchRequest*));
+    if(requests == NULL) {
+        return REQ_ABORTED;
+    }
+    
+    WebdavPList *prev_set = orig_request->set;
+    WebdavPList *prev_remove = orig_request->remove;
+    size_t set_count = orig_request->setcount;
+    size_t remove_count = orig_request->removecount;
+    
+    int ret = REQ_PROCEED;
+    
+    // iterate backends and execute proppatch_do
+    WebdavBackend *dav = op->dav;
+    size_t numrequests = 0;
+    while(dav) {
+        WebdavPList *set = webdav_plist_clone_s(
+                op->sn->pool,
+                prev_set,
+                &set_count);
+        WebdavPList *remove = webdav_plist_clone_s(
+                op->sn->pool,
+                prev_remove,
+                &remove_count);
+        if((prev_set && !set) || (prev_remove && !remove)) {
+            // clone failed, OOM
+            ret = REQ_ABORTED;
+            break;
+        }
+        
+        // create new WebdavProppatchRequest object for this backend
+        WebdavProppatchRequest *req = pool_malloc(
+                op->sn->pool,
+                sizeof(WebdavProppatchRequest));
+        memcpy(req, orig_request, sizeof(WebdavProppatchRequest));
+        req->set = set;
+        req->setcount = set_count;
+        req->remove = remove;
+        req->removecount = remove_count;
+        req->userdata = NULL;
+        
+        // check if we need to open the file because the backend want's it
+        if(!file && (dav->settings & WS_WEBDAV_PROPPATCH_USE_VFS)
+                         == WS_WEBDAV_PROPPATCH_USE_VFS)
+        {
+            ctx = vfs_request_context(op->sn, op->rq);
+            if(!ctx) {
+                ret = REQ_ABORTED;
+                break;
+            }
+            
+            file = vfs_open(ctx, path, O_RDONLY);
+            if(!file) {
+                protocol_status(
+                        op->sn,
+                        op->rq,
+                        util_errno2status(ctx->vfs_errno),
+                        NULL);
+                ret = REQ_ABORTED;
+            }
+        }
+        
+        // execute proppatch_do
+        if(dav->proppatch_do(req, resource, file, &set, &remove)) {
+            // return later, because we need do execute proppatch_finish
+            // for all successfully called backends
+            ret = REQ_ABORTED;
+            break;
+        }
+        
+        // proppatch_do should remove all handled props from set and remove
+        // in the next iteration, the backend must use these reduced lists
+        prev_set = set;
+        prev_remove = remove;
+        
+        requests[numrequests++] = req;
+        
+        // continue with next backend
+        dav = dav->next;
+    }
+    
+    WSBool commit = FALSE;
+    if(ret == REQ_PROCEED && resource->err == 0) {
+        // no errors, no properties with errors -> save the changes
+        commit = TRUE; 
+    }
+    
+    // call proppatch_finish for each successfully called proppatch_do
+    dav = op->dav;
+    int i = 0;
+    while(dav && i < numrequests) {
+        if(dav->proppatch_finish(requests[i], resource, file, commit)) {
+            ret = REQ_ABORTED;
+        }
+        i++;
+        dav = dav->next;
+    }
+    
+    if(file) {
+        vfs_close(file);
+    }
+    
+    if(resource->close(resource)) {
+        ret = REQ_ABORTED;
+    }
+    
+    return ret;
+}
+
 int webdav_op_proppatch_close_resource(
         WebdavOperation *op,
         WebdavResource *resource)
 {
-    return 0;
+    return 0; // NOP
 }
 

mercurial