# HG changeset patch # User Olaf Wintermann # Date 1577806289 -3600 # Node ID ff5826fc6a6c252e7452991cd4a812e04276552c # Parent 2915b6c11aec9805e94dab4960b46f2e9fee06b5 add href parameter to webdav_op_propfind_children diff -r 2915b6c11aec -r ff5826fc6a6c src/server/test/webdav.c --- a/src/server/test/webdav.c Tue Dec 31 14:53:13 2019 +0100 +++ b/src/server/test/webdav.c Tue Dec 31 16:31:29 2019 +0100 @@ -828,7 +828,7 @@ UCX_TEST_ASSERT(backend2_propfind_do_count == 1, "backend1 propfind_do not called") // propfind for all children - err = webdav_op_propfind_children(op, vfs, "/dir"); + err = webdav_op_propfind_children(op, vfs, "/", "/dir"); UCX_TEST_ASSERT(err == 0, "webdav_op_propfind_children failed"); // 1 dir + 4 children diff -r 2915b6c11aec -r ff5826fc6a6c src/server/webdav/operation.c --- a/src/server/webdav/operation.c Tue Dec 31 14:53:13 2019 +0100 +++ b/src/server/webdav/operation.c Tue Dec 31 16:31:29 2019 +0100 @@ -56,12 +56,12 @@ int webdav_op_propfind_begin( WebdavOperation *op, - const char *path, + const char *href, VFS_DIR parent, struct stat *s) { // create WebdavResource object for requested resource - WebdavResource *resource = op->response->addresource(op->response, path); + WebdavResource *resource = op->response->addresource(op->response, href); if(!resource) { return REQ_ABORTED; } @@ -89,44 +89,104 @@ return ret; } +typedef struct PathSearchElm { + char *href; + char *path; + size_t hreflen; + size_t pathlen; +} PathSearchElm; + +/* + * concats base + / + elm + * if baseinit is true, only elm is copied + */ +static int path_buf_concat( + pool_handle_t *pool, + char **buf, + size_t * restrict len, + WSBool * restrict baseinit, + const char *base, + size_t baselen, + const char *elm, + size_t elmlen) +{ + if(base[baselen-1] == '/') { + baselen--; + } + + size_t newlen = baselen + elmlen + 1; + if(newlen > WEBDAV_PATH_MAX) { + log_ereport(LOG_FAILURE, "webdav: maximal path length exceeded"); + return 1; + } + + // check if new path + terminator fits in the buffer + if(newlen + 1 > *len) { + *len = newlen + 128; + char *newbuf = pool_realloc(pool, *buf, newlen); + if(newbuf) { + log_ereport(LOG_FAILURE, "webdav: path memory allocation failed"); + return 1; + } + *baseinit = FALSE; + + *buf = newbuf; + } + + // if baseinit is true, the parent is already in the buffer + // and we don't need to memcpy it again + if(!(*baseinit)) { + memcpy(*buf, base, baselen); + (*buf)[baselen] = '/'; + *baseinit = TRUE; + } + // copy child and terminate string + memcpy((*buf) + baselen + 1, elm, elmlen); + (*buf)[newlen] = '\0'; + + return 0; +} + int webdav_op_propfind_children( WebdavOperation *op, VFSContext *vfs, - char *path) + const char *href, + const char *path) { WebdavPropfindRequest *request = op->requests->data; UcxAllocator *a = session_get_allocator(request->sn); pool_handle_t *pool = request->sn->pool; - UcxList *stack = ucx_list_prepend_a(a, NULL, path); + + 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 - char *newpath = NULL; - size_t newpathlen = 0; + // 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) { - char *cur_path = stack->data; - size_t parent_len = strlen(cur_path); - if(parent_len > WEBDAV_PATH_MAX) { - log_ereport(LOG_FAILURE, "webdav: maximal path length exceeded"); - err = 1; - break; - } - if(cur_path[parent_len-1] == '/') { - parent_len--; - } - size_t max_child_len = WEBDAV_PATH_MAX - parent_len; + 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, path); + VFS_DIR dir = vfs_opendir(vfs, cur_elm->path); if(!dir) { log_ereport( LOG_FAILURE, @@ -143,32 +203,36 @@ } size_t child_len = strlen(f.name); - if(child_len > max_child_len) { - log_ereport(LOG_FAILURE, "webdav: maximal path length exceeded"); + + // 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; } - size_t childpathlen = parent_len + child_len + 1; // +1 '/' - if(childpathlen > newpathlen) { - // we're gonna need a bigger boa^H^H^Hbuffer - if(newpath) { - pool_free(pool, newpath); - } - newpath = pool_malloc(pool, childpathlen + 1); - if(!newpath) { - err = 1; - break; - } - newpathlen = childpathlen; - path_buf_init = FALSE; + if(path_buf_concat( + pool, + &newpath, + &newpathlen, + &path_buf_init, + cur_elm->path, + cur_elm->pathlen, + f.name, + child_len)) + { + err = 1; + break; } - // create full path string for this child - if(!path_buf_init) { - memcpy(newpath, cur_path, parent_len); - newpath[parent_len] = '/'; - } - memcpy(newpath+parent_len+1, f.name, child_len); - newpath[childpathlen] = 0; + 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, newpath, dir, &f.stat)) { @@ -178,13 +242,25 @@ // 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'; - // add the newpath copy to the stack + 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, pathcp); + UcxList *newlistelm = ucx_list_append_a(a, stack_end, new_elm); if(!newlistelm) { err = 1; break; @@ -195,9 +271,10 @@ vfs_closedir(dir); - if(cur_path != path) { - pool_free(pool, cur_path); - } + 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); } diff -r 2915b6c11aec -r ff5826fc6a6c src/server/webdav/operation.h --- a/src/server/webdav/operation.h Tue Dec 31 14:53:13 2019 +0100 +++ b/src/server/webdav/operation.h Tue Dec 31 16:31:29 2019 +0100 @@ -53,14 +53,15 @@ int webdav_op_propfind_begin( WebdavOperation *op, - const char *path, + const char *href, VFS_DIR parent, struct stat *s); int webdav_op_propfind_children( WebdavOperation *op, VFSContext *vfs, - char *path); + const char *href, + const char *path); int webdav_op_propfiond_close_resource( WebdavOperation *op, diff -r 2915b6c11aec -r ff5826fc6a6c src/server/webdav/webdav.c --- a/src/server/webdav/webdav.c Tue Dec 31 14:53:13 2019 +0100 +++ b/src/server/webdav/webdav.c Tue Dec 31 16:31:29 2019 +0100 @@ -187,8 +187,9 @@ rq->davCollection : &default_backend; - // requested uri path + // requested uri and path char *path = pblock_findkeyval(pb_key_path, rq->vars); + char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb); // VFS settings are only taken from the first backend uint32_t settings = dav->settings; @@ -254,7 +255,7 @@ // depth is not 0 // in this case we need to execute propfind_do for all children if(usevfs) { - if(!webdav_op_propfind_children(op, vfs, path)) { + if(!webdav_op_propfind_children(op, vfs, uri, path)) { ret = REQ_ABORTED; } }