implement webdav delete for collections webdav

Sun, 31 May 2020 16:58:23 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 31 May 2020 16:58:23 +0200
branch
webdav
changeset 247
1df803e06076
parent 246
155bdef7fe7e
child 248
bc8f8ddbad2e

implement webdav delete for collections

src/server/daemon/vfs.c file | annotate | diff | comparison | revisions
src/server/daemon/vfs.h file | annotate | diff | comparison | revisions
src/server/public/vfs.h file | annotate | diff | comparison | revisions
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/daemon/vfs.c	Sun May 31 13:08:42 2020 +0200
+++ b/src/server/daemon/vfs.c	Sun May 31 16:58:23 2020 +0200
@@ -55,6 +55,7 @@
     sys_vfs_fdopendir,
     sys_vfs_mkdir,
     sys_vfs_unlink,
+    sys_vfs_rmdir,
     VFS_CHECKS_ACL,
     NULL
 };
@@ -267,6 +268,12 @@
     return vfs_path_op(ctx, path, ctx->vfs->unlink, ACL_DELETE);
 }
 
+int vfs_rmdir(VFSContext *ctx, const char *path) {
+    WS_ASSERT(ctx);
+    WS_ASSERT(path);
+    
+    return vfs_path_op(ctx, path, ctx->vfs->rmdir, ACL_DELETE);
+}
 
 // private
 int vfs_path_op(VFSContext *ctx, const char *path, vfs_op_f op, uint32_t access) {  
@@ -512,6 +519,10 @@
     return sys_path_op(ctx, path, sys_unlink);
 }
 
+int sys_vfs_rmdir(VFSContext *ctx, const char *path) {
+    return sys_path_op(ctx, path, sys_rmdir);
+}
+
 
 int sys_path_op(VFSContext *ctx, const char *path, sys_op_f op) {
     uint32_t access_mask = ctx->aclreqaccess;
@@ -667,6 +678,10 @@
     return unlink(path);
 }
 
+int sys_rmdir(VFSContext *ctx, const char *path, SysACL *sysacl) {
+    return rmdir(path);
+}
+
 /* public file api */
 
 NSAPI_PUBLIC int system_fread(SYS_FILE fd, void *buf, int nbyte) {
--- a/src/server/daemon/vfs.h	Sun May 31 13:08:42 2020 +0200
+++ b/src/server/daemon/vfs.h	Sun May 31 16:58:23 2020 +0200
@@ -60,6 +60,7 @@
 VFS_DIR sys_vfs_fdopendir(VFSContext *ctx, SYS_FILE fd);
 int sys_vfs_mkdir(VFSContext *ctx, const char *path);
 int sys_vfs_unlink(VFSContext *ctx, const char *path);
+int sys_vfs_rmdir(VFSContext *ctx, const char *path);
 
 int sys_path_op(VFSContext *ctx, const char *path, sys_op_f op);
 int sys_acl_check(VFSContext *ctx, uint32_t access_mask, SysACL *externacl);
@@ -79,6 +80,7 @@
 
 int sys_mkdir(VFSContext *ctx, const char *path, SysACL *sysacl);
 int sys_unlink(VFSContext *ctx, const char *path, SysACL *sysacl);
+int sys_rmdir(VFSContext *ctx, const char *path, SysACL *sysacl);
 
 void vfs_queue_aio(aiocb_s *aiocb, VFSAioOp op);
 
--- a/src/server/public/vfs.h	Sun May 31 13:08:42 2020 +0200
+++ b/src/server/public/vfs.h	Sun May 31 16:58:23 2020 +0200
@@ -55,6 +55,7 @@
     VFS_DIR (*fdopendir)(VFSContext *ctx, SYS_FILE fd);
     int (*mkdir)(VFSContext *ctx, const char *path);
     int (*unlink)(VFSContext *ctx, const char *path);
+    int (*rmdir)(VFSContext *Ctx, const char *path);
     uint32_t flags;
     void *instance;
 };
@@ -132,6 +133,7 @@
 void vfs_closedir(VFS_DIR dir);
 int vfs_mkdir(VFSContext *ctx, const char *path);
 int vfs_unlink(VFSContext *ctx, const char *path);
+int vfs_rmdir(VFSContext *ctx, const char *path);
 
 #ifdef	__cplusplus
 }
--- a/src/server/webdav/operation.c	Sun May 31 13:08:42 2020 +0200
+++ b/src/server/webdav/operation.c	Sun May 31 16:58:23 2020 +0200
@@ -444,6 +444,22 @@
     return op;
 }
 
+WebdavVFSOperation webdav_vfs_sub_op(
+        WebdavVFSOperation *op,
+        char *path,
+        struct stat *s)
+{
+    WebdavVFSOperation sub;
+    sub.dav = op->dav;
+    sub.path = path;
+    sub.sn = op->sn;
+    sub.vfs = op->vfs;
+    sub.path = op->path;
+    sub.stat = s;
+    sub.stat_errno = 0;
+    return sub;
+}
+
 int webdav_op_iterate_children(
         VFSContext *vfs,
         int depth,
@@ -456,10 +472,10 @@
     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);
+    start_elm->href = pool_strdup(pool, href ? href : "");
+    start_elm->path = pool_strdup(pool, path ? path : "");
+    start_elm->hreflen = href ? strlen(href) : 0;
+    start_elm->pathlen = path ? strlen(path) : 0;
     
     UcxList *stack = ucx_list_prepend_a(a, NULL, start_elm);
     UcxList *stack_end = stack;
@@ -724,20 +740,15 @@
 
 int webdav_vfs_unlink(WebdavVFSOperation *op) {
     // stat the file first, to check if the file is a directory
-    // deletion of simple files can be done just here,
-    // whereas deleting directories is more complicated
     if(webdav_vfs_stat(op)) {
         return 1; // error
     } else {
-        int r = 0;
         if(!S_ISDIR(op->stat->st_mode)) {
             return vfs_unlink(op->vfs, op->path);
+        } else {
+            return vfs_rmdir(op->vfs, op->path);
         }
     }
     
-    // delete directory:
-    
-    
-    
     return 0;
 }
--- a/src/server/webdav/operation.h	Sun May 31 13:08:42 2020 +0200
+++ b/src/server/webdav/operation.h	Sun May 31 16:58:23 2020 +0200
@@ -140,6 +140,11 @@
         WebdavBackend *dav,
         WSBool precondition);
 
+WebdavVFSOperation webdav_vfs_sub_op(
+        WebdavVFSOperation *op,
+        char *path,
+        struct stat *s);
+
 int webdav_op_iterate_children(
         VFSContext *vfs,
         int depth,
--- a/src/server/webdav/webdav.c	Sun May 31 13:08:42 2020 +0200
+++ b/src/server/webdav/webdav.c	Sun May 31 16:58:23 2020 +0200
@@ -461,9 +461,101 @@
     return REQ_ABORTED;
 }
 
+typedef struct DeleteFile {
+    char *path;
+    struct stat s;
+} DeleteFile;
+
+typedef struct DeleteLists {
+    UcxAllocator *a;
+    UcxList *dirs_begin;
+    UcxList *dirs_end;
+    UcxList *files_begin;
+    UcxList *files_end;
+} DeleteOp;
+
+static int deletelist_add(
+        VFSContext *vfs,
+        const char *href,
+        const char *path,
+        VFSDir *parent,
+        struct stat *s,
+        void *userdata)
+{
+    DeleteOp *op = userdata;
+    
+    // create object for this file
+    DeleteFile *file = almalloc(op->a, sizeof(DeleteFile));
+    if(!file) {
+        return 1;
+    }
+    file->path = sstrdup_a(op->a, sstr((char*)path)).ptr;
+    if(!file->path) {
+        return 1;
+    }
+    file->s = *s;
+    
+    // determine which list to use
+    UcxList **begin;
+    UcxList **end;
+    if(S_ISDIR(s->st_mode)) {
+        begin = &op->dirs_begin;
+        end = &op->dirs_end;
+    } else {
+        begin = &op->files_begin;
+        end = &op->files_end;
+    }
+    
+    // add file to list
+    UcxList *elm = ucx_list_append_a(op->a, NULL, file);
+    if(!elm) {
+        alfree(op->a, file->path); // at least do some cleanup, although it
+        alfree(op->a, file);       // isn't really necessary
+        return 1;
+    }
+    if(*begin == NULL) {
+        *begin = elm;
+        *end = elm;
+    } else {
+        ucx_list_concat(*end, elm);
+        *end = elm;
+    }
+    
+    return 0;
+}
+
 static int webdav_delete_collection(WebdavVFSOperation *op)
 {
-    // TODO
+    DeleteOp del;
+    ZERO(&del, sizeof(DeleteOp));
+    del.a = session_get_allocator(op->sn);
+    
+    // get a list of all files
+    if(webdav_op_iterate_children(op->vfs, -1, NULL, op->path,
+            deletelist_add, &del))
+    {
+        return 1;
+    }
+    
+    // delete files first
+    UCX_FOREACH(elm, del.files_begin) {
+        DeleteFile *file = elm->data;
+        WebdavVFSOperation sub = webdav_vfs_sub_op(op, file->path, &file->s);
+        if(webdav_vfs_op_do(&sub, WEBDAV_VFS_DELETE)) {
+            return 1;
+        }
+    }
+    
+    // delete directories, reverse order
+    for(UcxList *elm=del.dirs_end;elm;elm=elm->prev) {
+        DeleteFile *file = elm->data;
+        WebdavVFSOperation sub = webdav_vfs_sub_op(op, file->path, &file->s);
+        if(webdav_vfs_op_do(&sub, WEBDAV_VFS_DELETE)) {
+            return 1;
+        }
+    }
+    
+    return 0;
 }
 
 int webdav_delete(pblock *pb, Session *sn, Request *rq) { 

mercurial