Sun, 31 May 2020 13:08:42 +0200
add webdav op function for iterating directories
--- 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; }