# HG changeset patch # User Olaf Wintermann # Date 1590937103 -7200 # Node ID 1df803e06076c06a187f0230f3cd91abdb0b478e # Parent 155bdef7fe7ebb531923af2fe471d42e6496048c implement webdav delete for collections diff -r 155bdef7fe7e -r 1df803e06076 src/server/daemon/vfs.c --- 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) { diff -r 155bdef7fe7e -r 1df803e06076 src/server/daemon/vfs.h --- 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); diff -r 155bdef7fe7e -r 1df803e06076 src/server/public/vfs.h --- 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 } diff -r 155bdef7fe7e -r 1df803e06076 src/server/webdav/operation.c --- 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; } diff -r 155bdef7fe7e -r 1df803e06076 src/server/webdav/operation.h --- 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, diff -r 155bdef7fe7e -r 1df803e06076 src/server/webdav/webdav.c --- 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) {