add webdav op function for iterating directories webdav

Sun, 31 May 2020 13:08:42 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 31 May 2020 13:08:42 +0200
branch
webdav
changeset 246
155bdef7fe7e
parent 245
a193c42fc809
child 247
1df803e06076

add webdav op function for iterating directories

src/server/webdav/operation.c file | annotate | diff | comparison | revisions
src/server/webdav/operation.h file | annotate | diff | comparison | revisions
src/server/webdav/webdav.c file | annotate | diff | comparison | revisions
--- a/src/server/webdav/operation.c	Sun Feb 02 17:42:05 2020 +0100
+++ b/src/server/webdav/operation.c	Sun May 31 13:08:42 2020 +0200
@@ -170,6 +170,17 @@
     return 0;
 }
 
+static int propfind_child_cb(
+        VFSContext *vfs,
+        const char *href,
+        const char *path,
+        VFSDir *parent,
+        struct stat *s,
+        void *op)
+{
+    return webdav_op_propfind_begin(op, href, parent, s);
+}
+
 int webdav_op_propfind_children(
         WebdavOperation *op,
         VFSContext *vfs,
@@ -177,139 +188,8 @@
         const char *path)
 {
     WebdavPropfindRequest *request = op->requests->data;
-    
-    UcxAllocator *a = session_get_allocator(request->sn);
-    pool_handle_t *pool = request->sn->pool;
-    
-    PathSearchElm *start_elm = pool_malloc(pool, sizeof(PathSearchElm));
-    start_elm->href = pool_strdup(pool, href);
-    start_elm->path = pool_strdup(pool, path);
-    start_elm->hreflen = strlen(href);
-    start_elm->pathlen = strlen(path);
-    
-    UcxList *stack = ucx_list_prepend_a(a, NULL, start_elm);
-    UcxList *stack_end = stack;
-    if(!stack) {
-        return 1;
-    }
-    
-    // reusable buffer for full child path and href
-    char *newpath = pool_malloc(pool, 256);
-    size_t newpathlen = 256;
-    
-    char *newhref = pool_malloc(pool, 256);
-    size_t newhreflen = 256;
-    
-    int err = 0;
-    while(stack && !err) {
-        PathSearchElm *cur_elm = stack->data;
-        
-        // when newpath is initialized with the parent path
-        // set path_buf_init to TRUE
-        WSBool href_buf_init = FALSE;
-        WSBool path_buf_init = FALSE;
-        
-        VFS_DIR dir = vfs_opendir(vfs, cur_elm->path);
-        if(!dir) {
-            log_ereport(
-                    LOG_FAILURE,
-                    "webdav: propfind: cannot open directory %d",
-                    vfs->vfs_errno);
-            err = 1;
-            break;
-        }
-        
-        VFS_ENTRY f;
-        while(vfs_readdir_stat(dir, &f)) {
-            if(f.stat_errno != 0) {
-                continue;
-            }
-            
-            size_t child_len = strlen(f.name);
-            
-            // create new path and href for the child
-            if(path_buf_concat(
-                    pool,
-                    &newhref,
-                    &newhreflen,
-                    &href_buf_init,
-                    cur_elm->href,
-                    cur_elm->hreflen,
-                    f.name,
-                    child_len))
-            {
-                err = 1;
-                break;
-            }
-            if(path_buf_concat(
-                    pool,
-                    &newpath,
-                    &newpathlen,
-                    &path_buf_init,
-                    cur_elm->path,
-                    cur_elm->pathlen,
-                    f.name,
-                    child_len))
-            {
-                err = 1;
-                break;
-            }
-            size_t childhreflen = cur_elm->hreflen + 1 + child_len;
-            size_t childpathlen = cur_elm->pathlen + 1 + child_len;
-            
-            // propfind for this child
-            if(webdav_op_propfind_begin(op, newhref, dir, &f.stat)) {
-                err = 1;
-                break;
-            }
-            
-            // depth of -1 means infinity
-            if(request->depth == -1 && S_ISDIR(f.stat.st_mode)) {
-                char *hrefcp = pool_malloc(pool, childhreflen + 1);
-                memcpy(hrefcp, newhref, childhreflen + 1);
-                hrefcp[childhreflen] = '\0';
-                
-                char *pathcp = pool_malloc(pool, childpathlen + 1);
-                memcpy(pathcp, newpath, childpathlen + 1);
-                pathcp[childpathlen] = '\0';
-                
-                PathSearchElm *new_elm = pool_malloc(pool,
-                                            sizeof(PathSearchElm));
-                new_elm->href = hrefcp;
-                new_elm->path = pathcp;
-                new_elm->hreflen = childhreflen;
-                new_elm->pathlen = childpathlen;
-                
-                // add the new_elm to the stack
-                // stack_end is always not NULL here, because we remove
-                // the first stack element at the end of the loop
-                UcxList *newlistelm = ucx_list_append_a(a, stack_end, new_elm);
-                if(!newlistelm) {
-                    err = 1;
-                    break;
-                }
-                stack_end = newlistelm;
-            }
-        }
-        
-        vfs_closedir(dir);
-        
-        pool_free(pool, cur_elm->path);
-        pool_free(pool, cur_elm->href);
-        pool_free(pool, cur_elm);
-        
-        stack = ucx_list_remove_a(a, stack, stack);
-    }
-    
-    // in case of an error, we have to free all remaining stack elements
-    UCX_FOREACH(elm, stack) {
-        char *data = elm->data;
-        if(data != path) {
-            pool_free(pool, data);
-        }
-    }
-    
-    return err;
+    return webdav_op_iterate_children(
+            vfs, request->depth, href, path, propfind_child_cb, op);
 }
 
 int webdav_op_propfiond_close_resource(
@@ -564,6 +444,149 @@
     return op;
 }
 
+int webdav_op_iterate_children(
+        VFSContext *vfs,
+        int depth,
+        const char *href,
+        const char *path,
+        vfs_op_child_func func,
+        void *userdata)
+{
+    UcxAllocator *a = session_get_allocator(vfs->sn);
+    pool_handle_t *pool = vfs->sn->pool;
+    
+    PathSearchElm *start_elm = pool_malloc(pool, sizeof(PathSearchElm));
+    start_elm->href = pool_strdup(pool, href);
+    start_elm->path = pool_strdup(pool, path);
+    start_elm->hreflen = strlen(href);
+    start_elm->pathlen = strlen(path);
+    
+    UcxList *stack = ucx_list_prepend_a(a, NULL, start_elm);
+    UcxList *stack_end = stack;
+    if(!stack) {
+        return 1;
+    }
+    
+    // reusable buffer for full child path and href
+    char *newpath = pool_malloc(pool, 256);
+    size_t newpathlen = 256;
+    
+    char *newhref = pool_malloc(pool, 256);
+    size_t newhreflen = 256;
+    
+    int err = 0;
+    while(stack && !err) {
+        PathSearchElm *cur_elm = stack->data;
+        
+        // when newpath is initialized with the parent path
+        // set path_buf_init to TRUE
+        WSBool href_buf_init = FALSE;
+        WSBool path_buf_init = FALSE;
+        
+        VFS_DIR dir = vfs_opendir(vfs, cur_elm->path);
+        if(!dir) {
+            log_ereport(
+                    LOG_FAILURE,
+                    "webdav: propfind: cannot open directory %d",
+                    vfs->vfs_errno);
+            err = 1;
+            break;
+        }
+        
+        VFS_ENTRY f;
+        while(vfs_readdir_stat(dir, &f)) {
+            if(f.stat_errno != 0) {
+                continue;
+            }
+            
+            size_t child_len = strlen(f.name);
+            
+            // create new path and href for the child
+            if(path_buf_concat(
+                    pool,
+                    &newhref,
+                    &newhreflen,
+                    &href_buf_init,
+                    cur_elm->href,
+                    cur_elm->hreflen,
+                    f.name,
+                    child_len))
+            {
+                err = 1;
+                break;
+            }
+            if(path_buf_concat(
+                    pool,
+                    &newpath,
+                    &newpathlen,
+                    &path_buf_init,
+                    cur_elm->path,
+                    cur_elm->pathlen,
+                    f.name,
+                    child_len))
+            {
+                err = 1;
+                break;
+            }
+            size_t childhreflen = cur_elm->hreflen + 1 + child_len;
+            size_t childpathlen = cur_elm->pathlen + 1 + child_len;
+            
+            // execute callback func for this file
+            if(func(vfs, newhref, newpath, dir, &f.stat, userdata)) {
+                err = 1;
+                break;
+            }
+            
+            // depth of -1 means infinity
+            if(depth == -1 && S_ISDIR(f.stat.st_mode)) {
+                char *hrefcp = pool_malloc(pool, childhreflen + 1);
+                memcpy(hrefcp, newhref, childhreflen + 1);
+                hrefcp[childhreflen] = '\0';
+                
+                char *pathcp = pool_malloc(pool, childpathlen + 1);
+                memcpy(pathcp, newpath, childpathlen + 1);
+                pathcp[childpathlen] = '\0';
+                
+                PathSearchElm *new_elm = pool_malloc(pool,
+                                            sizeof(PathSearchElm));
+                new_elm->href = hrefcp;
+                new_elm->path = pathcp;
+                new_elm->hreflen = childhreflen;
+                new_elm->pathlen = childpathlen;
+                
+                // add the new_elm to the stack
+                // stack_end is always not NULL here, because we remove
+                // the first stack element at the end of the loop
+                UcxList *newlistelm = ucx_list_append_a(a, stack_end, new_elm);
+                if(!newlistelm) {
+                    err = 1;
+                    break;
+                }
+                stack_end = newlistelm;
+            }
+        }
+        
+        vfs_closedir(dir);
+        
+        pool_free(pool, cur_elm->path);
+        pool_free(pool, cur_elm->href);
+        pool_free(pool, cur_elm);
+        
+        stack = ucx_list_remove_a(a, stack, stack);
+    }
+    
+    // in case of an error, we have to free all remaining stack elements
+    UCX_FOREACH(elm, stack) {
+        char *data = elm->data;
+        if(data != path) {
+            pool_free(pool, data);
+        }
+    }
+    
+    return err;
+}
+
+
 int webdav_vfs_stat(WebdavVFSOperation *op) {
     if(op->stat) {
         return 0;
--- a/src/server/webdav/operation.h	Sun Feb 02 17:42:05 2020 +0100
+++ b/src/server/webdav/operation.h	Sun May 31 13:08:42 2020 +0200
@@ -78,6 +78,14 @@
 typedef int(*vfs_op_func)(WebdavVFSRequest *, WSBool *);
 typedef int(*vfs_op_finish_func)(WebdavVFSRequest *, WSBool);
 
+typedef int(*vfs_op_child_func)(
+        VFSContext *,
+        const char *,                     /* href */
+        const char *,                     /* path */
+        VFSDir *,                         /* parent dir */
+        struct stat *,                    /* child stat */
+        void *);                          /* user data */
+
 /*
  * counts the number of backends
  */
@@ -132,6 +140,14 @@
         WebdavBackend *dav,
         WSBool precondition);
 
+int webdav_op_iterate_children(
+        VFSContext *vfs,
+        int depth,
+        const char *href,
+        const char *path,
+        vfs_op_child_func func,
+        void *userdata);
+
 int webdav_vfs_stat(WebdavVFSOperation *op);
 
 int webdav_vfs_op_do(WebdavVFSOperation *op, WebdavVFSOpType type);
--- a/src/server/webdav/webdav.c	Sun Feb 02 17:42:05 2020 +0100
+++ b/src/server/webdav/webdav.c	Sun May 31 13:08:42 2020 +0200
@@ -46,6 +46,7 @@
 #include "../daemon/session.h"
 #include "../daemon/http.h"
 #include "../daemon/protocol.h"
+#include "../daemon/vfs.h"
 
 static UcxMap *method_handler_map;
 
@@ -460,13 +461,9 @@
     return REQ_ABORTED;
 }
 
-static int webdav_delete_collection(
-        Session *sn,
-        Request *rq,
-        VFSContext *vfs,
-        const char *path)
+static int webdav_delete_collection(WebdavVFSOperation *op)
 {
-    
+    // TODO
 }
 
 int webdav_delete(pblock *pb, Session *sn, Request *rq) { 
@@ -475,7 +472,19 @@
         return REQ_ABORTED;
     }
     
-    int ret = webdav_vfs_op_do(op, WEBDAV_VFS_MKDIR);
+    // stat to find out if the resource is a collection
+    struct stat s;
+    if(vfs_stat(op->vfs, op->path, &s)) {
+        sys_set_error_status(op->vfs);
+        return REQ_ABORTED;
+    }
+    
+    int ret;
+    if(S_ISDIR(s.st_mode)) {
+        ret = webdav_delete_collection(op);
+    } else {
+        ret = webdav_vfs_op_do(op, WEBDAV_VFS_DELETE);
+    }
     
     return ret;
 }

mercurial