From 1aa6e5d49746fefd1d8bb6461a1199e2c597770b Mon Sep 17 00:00:00 2001 From: Greg Stein Date: Thu, 9 Nov 2000 11:23:39 +0000 Subject: [PATCH] first round whack at cleaning up the walker interface git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@86884 13f79535-47bb-0310-9956-ffa450edef68 --- modules/dav/fs/repos.c | 203 +++++++++++++++++++---------------- modules/dav/main/mod_dav.c | 55 +++++----- modules/dav/main/mod_dav.h | 81 +++++++++----- modules/dav/main/util.c | 32 +++--- modules/dav/main/util_lock.c | 86 ++++++++------- 5 files changed, 255 insertions(+), 202 deletions(-) diff --git a/modules/dav/fs/repos.c b/modules/dav/fs/repos.c index 8b8606a441..ac9de83925 100644 --- a/modules/dav/fs/repos.c +++ b/modules/dav/fs/repos.c @@ -83,7 +83,11 @@ struct dav_resource_private { /* private context for doing a filesystem walk */ typedef struct { - dav_walker_ctx *wctx; + /* the input walk parameters */ + const dav_walk_params *params; + + /* reused as we walk */ + dav_walk_resource wres; dav_resource res1; dav_resource res2; @@ -92,6 +96,8 @@ typedef struct { dav_buffer path1; dav_buffer path2; + dav_buffer uri_buf; /* URI for res1 */ + dav_buffer locknull_buf; } dav_fs_walker_context; @@ -907,13 +913,15 @@ static dav_error * dav_fs_create_collection(dav_resource *resource) return NULL; } -static dav_error * dav_fs_copymove_walker(dav_walker_ctx *ctx, int calltype) +static dav_error * dav_fs_copymove_walker(dav_walk_resource *wres, + int calltype) { - dav_resource_private *srcinfo = ctx->resource->info; - dav_resource_private *dstinfo = ctx->res2->info; + dav_walker_ctx *ctx = wres->walk_ctx; + dav_resource_private *srcinfo = wres->resource->info; + dav_resource_private *dstinfo = wres->res_dst->info; dav_error *err = NULL; - if (ctx->resource->collection) { + if (wres->resource->collection) { if (calltype == DAV_CALLTYPE_POSTFIX) { /* Postfix call for MOVE. delete the source dir. * Note: when copying, we do not enable the postfix-traversal. @@ -923,16 +931,16 @@ static dav_error * dav_fs_copymove_walker(dav_walker_ctx *ctx, int calltype) } else { /* copy/move of a collection. Create the new, target collection */ - if (apr_make_dir(dstinfo->pathname, APR_OS_DEFAULT, ctx->pool) - != APR_SUCCESS) { + if (apr_make_dir(dstinfo->pathname, APR_OS_DEFAULT, + ctx->w.pool) != APR_SUCCESS) { /* ### assume it was a permissions problem */ /* ### need a description here */ - err = dav_new_error(ctx->pool, HTTP_FORBIDDEN, 0, NULL); + err = dav_new_error(ctx->w.pool, HTTP_FORBIDDEN, 0, NULL); } } } else { - err = dav_fs_copymove_file(ctx->is_move, ctx->pool, + err = dav_fs_copymove_file(ctx->is_move, ctx->w.pool, srcinfo->pathname, dstinfo->pathname, &ctx->work_buf); /* ### push a higher-level description? */ @@ -953,9 +961,9 @@ static dav_error * dav_fs_copymove_walker(dav_walker_ctx *ctx, int calltype) if (err != NULL && !ap_is_HTTP_SERVER_ERROR(err->status) && (ctx->is_move - || !dav_fs_is_same_resource(ctx->resource, ctx->root))) { + || !dav_fs_is_same_resource(wres->resource, ctx->w.root))) { /* ### use errno to generate DAV:responsedescription? */ - dav_add_response(ctx, ctx->resource->uri, err->status, NULL); + dav_add_response(wres, err->status, NULL); /* the error is in the multistatus now. do not stop the traversal. */ return NULL; @@ -980,18 +988,20 @@ static dav_error *dav_fs_copymove_resource( * including the state dirs */ if (src->collection) { - dav_walker_ctx ctx = { 0 }; + dav_walker_ctx ctx = { { 0 } }; + + ctx.w.walk_type = DAV_WALKTYPE_ALL | DAV_WALKTYPE_HIDDEN; + ctx.w.func = dav_fs_copymove_walker; + ctx.w.walk_ctx = &ctx; + ctx.w.pool = src->info->pool; + ctx.w.root = src; + ctx.w.root_dst = dst; - ctx.walk_type = DAV_WALKTYPE_ALL | DAV_WALKTYPE_HIDDEN; - ctx.func = dav_fs_copymove_walker; - ctx.pool = src->info->pool; - ctx.resource = src; - ctx.res2 = dst; ctx.is_move = is_move; - ctx.postfix = is_move; /* needed for MOVE to delete source dirs */ - /* copy over the source URI */ - dav_buffer_init(ctx.pool, &ctx.uri, src->uri); + /* postfix is needed for MOVE to delete source dirs */ + if (is_move) + ctx.w.walk_type |= DAV_WALKTYPE_POSTFIX; if ((err = dav_fs_walk(&ctx, depth)) != NULL) { /* on a "real" error, then just punt. nothing else to do. */ @@ -1167,19 +1177,19 @@ static dav_error * dav_fs_move_resource( err); } -static dav_error * dav_fs_delete_walker(dav_walker_ctx *ctx, int calltype) +static dav_error * dav_fs_delete_walker(dav_walk_resource *wres, int calltype) { - dav_resource_private *info = ctx->resource->info; + dav_resource_private *info = wres->resource->info; /* do not attempt to remove a null resource, * or a collection with children */ - if (ctx->resource->exists && - (!ctx->resource->collection || calltype == DAV_CALLTYPE_POSTFIX)) { + if (wres->resource->exists && + (!wres->resource->collection || calltype == DAV_CALLTYPE_POSTFIX)) { /* try to remove the resource */ int result; - result = ctx->resource->collection + result = wres->resource->collection ? rmdir(info->pathname) : remove(info->pathname); @@ -1194,7 +1204,7 @@ static dav_error * dav_fs_delete_walker(dav_walker_ctx *ctx, int calltype) /* ### assume there is a permissions problem */ /* ### use errno to generate DAV:responsedescription? */ - dav_add_response(ctx, ctx->resource->uri, HTTP_FORBIDDEN, NULL); + dav_add_response(wres, HTTP_FORBIDDEN, NULL); } } @@ -1212,16 +1222,16 @@ static dav_error * dav_fs_remove_resource(dav_resource *resource, * including the state dirs */ if (resource->collection) { - dav_walker_ctx ctx = { 0 }; + dav_walker_ctx ctx = { { 0 } }; dav_error *err = NULL; - ctx.walk_type = DAV_WALKTYPE_ALL | DAV_WALKTYPE_HIDDEN; - ctx.postfix = 1; - ctx.func = dav_fs_delete_walker; - ctx.pool = info->pool; - ctx.resource = resource; - - dav_buffer_init(info->pool, &ctx.uri, resource->uri); + ctx.w.walk_type = (DAV_WALKTYPE_ALL + | DAV_WALKTYPE_HIDDEN + | DAV_WALKTYPE_POSTFIX); + ctx.w.func = dav_fs_delete_walker; + ctx.w.walk_ctx = &ctx; + ctx.w.pool = info->pool; + ctx.w.root = resource; if ((err = dav_fs_walk(&ctx, DAV_INFINITY)) != NULL) { /* on a "real" error, then just punt. nothing else to do. */ @@ -1261,16 +1271,17 @@ static dav_error * dav_fs_remove_resource(dav_resource *resource, * including lock-null resources as we go. */ static dav_error * dav_fs_walker(dav_fs_walker_context *fsctx, int depth) { + const dav_walk_params *params = fsctx->params; + apr_pool_t *pool = params->pool; dav_error *err = NULL; - dav_walker_ctx *wctx = fsctx->wctx; - int isdir = wctx->resource->collection; + int isdir = fsctx->res1.collection; apr_dir_t *dirp; /* ensure the context is prepared properly, then call the func */ - err = (*wctx->func)(wctx, - isdir - ? DAV_CALLTYPE_COLLECTION - : DAV_CALLTYPE_MEMBER); + err = (*params->func)(&fsctx->wres, + isdir + ? DAV_CALLTYPE_COLLECTION + : DAV_CALLTYPE_MEMBER); if (err != NULL) { return err; } @@ -1281,13 +1292,13 @@ static dav_error * dav_fs_walker(dav_fs_walker_context *fsctx, int depth) /* put a trailing slash onto the directory, in preparation for appending * files to it as we discovery them within the directory */ - dav_check_bufsize(wctx->pool, &fsctx->path1, DAV_BUFFER_PAD); + dav_check_bufsize(pool, &fsctx->path1, DAV_BUFFER_PAD); fsctx->path1.buf[fsctx->path1.cur_len++] = '/'; fsctx->path1.buf[fsctx->path1.cur_len] = '\0'; /* in pad area */ /* if a secondary path is present, then do that, too */ if (fsctx->path2.buf != NULL) { - dav_check_bufsize(wctx->pool, &fsctx->path2, DAV_BUFFER_PAD); + dav_check_bufsize(pool, &fsctx->path2, DAV_BUFFER_PAD); fsctx->path2.buf[fsctx->path2.cur_len++] = '/'; fsctx->path2.buf[fsctx->path2.cur_len] = '\0'; /* in pad area */ } @@ -1302,9 +1313,9 @@ static dav_error * dav_fs_walker(dav_fs_walker_context *fsctx, int depth) fsctx->res2.collection = 0; /* open and scan the directory */ - if ((apr_opendir(&dirp, fsctx->path1.buf, wctx->pool)) != APR_SUCCESS) { + if ((apr_opendir(&dirp, fsctx->path1.buf, pool)) != APR_SUCCESS) { /* ### need a better error */ - return dav_new_error(wctx->pool, HTTP_NOT_FOUND, 0, NULL); + return dav_new_error(pool, HTTP_NOT_FOUND, 0, NULL); } while ((apr_readdir(dirp)) == APR_SUCCESS) { char *name; @@ -1318,7 +1329,7 @@ static dav_error * dav_fs_walker(dav_fs_walker_context *fsctx, int depth) continue; } - if (wctx->walk_type & DAV_WALKTYPE_AUTH) { + if (params->walk_type & DAV_WALKTYPE_AUTH) { /* ### need to authorize each file */ /* ### example: .htaccess is normally configured to fail auth */ @@ -1328,28 +1339,28 @@ static dav_error * dav_fs_walker(dav_fs_walker_context *fsctx, int depth) } } /* skip the state dir unless a HIDDEN is performed */ - if (!(wctx->walk_type & DAV_WALKTYPE_HIDDEN) + if (!(params->walk_type & DAV_WALKTYPE_HIDDEN) && !strcmp(name, DAV_FS_STATE_DIR)) { continue; } /* append this file onto the path buffer (copy null term) */ - dav_buffer_place_mem(wctx->pool, &fsctx->path1, name, len + 1, 0); + dav_buffer_place_mem(pool, &fsctx->path1, name, len + 1, 0); - if (apr_lstat(&fsctx->info1.finfo, fsctx->path1.buf, wctx->pool) != 0) { + if (apr_lstat(&fsctx->info1.finfo, fsctx->path1.buf, pool) != 0) { /* woah! where'd it go? */ /* ### should have a better error here */ - err = dav_new_error(wctx->pool, HTTP_NOT_FOUND, 0, NULL); + err = dav_new_error(pool, HTTP_NOT_FOUND, 0, NULL); break; } /* copy the file to the URI, too. NOTE: we will pad an extra byte for the trailing slash later. */ - dav_buffer_place_mem(wctx->pool, &wctx->uri, name, len + 1, 1); + dav_buffer_place_mem(pool, &fsctx->uri_buf, name, len + 1, 1); /* if there is a secondary path, then do that, too */ if (fsctx->path2.buf != NULL) { - dav_buffer_place_mem(wctx->pool, &fsctx->path2, name, len + 1, 0); + dav_buffer_place_mem(pool, &fsctx->path2, name, len + 1, 0); } /* set up the (internal) pathnames for the two resources */ @@ -1357,19 +1368,20 @@ static dav_error * dav_fs_walker(dav_fs_walker_context *fsctx, int depth) fsctx->info2.pathname = fsctx->path2.buf; /* set up the URI for the current resource */ - fsctx->res1.uri = wctx->uri.buf; + fsctx->res1.uri = fsctx->uri_buf.buf; /* ### for now, only process regular files (e.g. skip symlinks) */ if (fsctx->info1.finfo.filetype == APR_REG) { /* call the function for the specified dir + file */ - if ((err = (*wctx->func)(wctx, DAV_CALLTYPE_MEMBER)) != NULL) { + if ((err = (*params->func)(&fsctx->wres, + DAV_CALLTYPE_MEMBER)) != NULL) { /* ### maybe add a higher-level description? */ break; } } else if (fsctx->info1.finfo.filetype == APR_DIR) { size_t save_path_len = fsctx->path1.cur_len; - size_t save_uri_len = wctx->uri.cur_len; + size_t save_uri_len = fsctx->uri_buf.cur_len; size_t save_path2_len = fsctx->path2.cur_len; /* adjust length to incorporate the subdir name */ @@ -1377,9 +1389,9 @@ static dav_error * dav_fs_walker(dav_fs_walker_context *fsctx, int depth) fsctx->path2.cur_len += len; /* adjust URI length to incorporate subdir and a slash */ - wctx->uri.cur_len += len + 1; - wctx->uri.buf[wctx->uri.cur_len - 1] = '/'; - wctx->uri.buf[wctx->uri.cur_len] = '\0'; + fsctx->uri_buf.cur_len += len + 1; + fsctx->uri_buf.buf[fsctx->uri_buf.cur_len - 1] = '/'; + fsctx->uri_buf.buf[fsctx->uri_buf.cur_len] = '\0'; /* switch over to a collection */ fsctx->res1.collection = 1; @@ -1395,7 +1407,7 @@ static dav_error * dav_fs_walker(dav_fs_walker_context *fsctx, int depth) /* put the various information back */ fsctx->path1.cur_len = save_path_len; fsctx->path2.cur_len = save_path2_len; - wctx->uri.cur_len = save_uri_len; + fsctx->uri_buf.cur_len = save_uri_len; fsctx->res1.collection = 0; fsctx->res2.collection = 0; @@ -1410,7 +1422,7 @@ static dav_error * dav_fs_walker(dav_fs_walker_context *fsctx, int depth) if (err != NULL) return err; - if (wctx->walk_type & DAV_WALKTYPE_LOCKNULL) { + if (params->walk_type & DAV_WALKTYPE_LOCKNULL) { size_t offset = 0; /* null terminate the directory name */ @@ -1441,12 +1453,12 @@ static dav_error * dav_fs_walker(dav_fs_walker_context *fsctx, int depth) ** we don't have to pad the URI for a slash since a locknull ** resource is not a collection. */ - dav_buffer_place_mem(wctx->pool, &fsctx->path1, + dav_buffer_place_mem(pool, &fsctx->path1, fsctx->locknull_buf.buf + offset, len + 1, 0); - dav_buffer_place_mem(wctx->pool, &wctx->uri, + dav_buffer_place_mem(pool, &fsctx->uri_buf, fsctx->locknull_buf.buf + offset, len + 1, 0); if (fsctx->path2.buf != NULL) { - dav_buffer_place_mem(wctx->pool, &fsctx->path2, + dav_buffer_place_mem(pool, &fsctx->path2, fsctx->locknull_buf.buf + offset, len + 1, 0); } @@ -1456,7 +1468,7 @@ static dav_error * dav_fs_walker(dav_fs_walker_context *fsctx, int depth) fsctx->info2.pathname = fsctx->path2.buf; /* set up the URI for the current resource */ - fsctx->res1.uri = wctx->uri.buf; + fsctx->res1.uri = fsctx->uri_buf.buf; /* ** To prevent a PROPFIND showing an expired locknull @@ -1488,14 +1500,16 @@ static dav_error * dav_fs_walker(dav_fs_walker_context *fsctx, int depth) ### even the resolve func would probably fail when it ### tried to find a timed-out direct lock). */ - if ((err = dav_lock_query(wctx->lockdb, wctx->resource, &locks)) != NULL) { + if ((err = dav_lock_query(params->lockdb, &fsctx->res1, + &locks)) != NULL) { /* ### maybe add a higher-level description? */ return err; } /* call the function for the specified dir + file */ if (locks != NULL && - (err = (*wctx->func)(wctx, DAV_CALLTYPE_LOCKNULL)) != NULL) { + (err = (*params->func)(&fsctx->wres, + DAV_CALLTYPE_LOCKNULL)) != NULL) { /* ### maybe add a higher-level description? */ return err; } @@ -1507,10 +1521,10 @@ static dav_error * dav_fs_walker(dav_fs_walker_context *fsctx, int depth) fsctx->res1.exists = 1; } - if (wctx->postfix) { + if (params->walk_type & DAV_WALKTYPE_POSTFIX) { /* replace the dirs' trailing slashes with null terms */ fsctx->path1.buf[--fsctx->path1.cur_len] = '\0'; - wctx->uri.buf[--wctx->uri.cur_len] = '\0'; + fsctx->uri_buf.buf[--fsctx->uri_buf.cur_len] = '\0'; if (fsctx->path2.buf != NULL) { fsctx->path2.buf[--fsctx->path2.cur_len] = '\0'; } @@ -1518,7 +1532,7 @@ static dav_error * dav_fs_walker(dav_fs_walker_context *fsctx, int depth) /* this is a collection which exists */ fsctx->res1.collection = 1; - return (*wctx->func)(wctx, DAV_CALLTYPE_POSTFIX); + return (*params->func)(&fsctx->wres, DAV_CALLTYPE_POSTFIX); } return NULL; @@ -1526,60 +1540,57 @@ static dav_error * dav_fs_walker(dav_fs_walker_context *fsctx, int depth) static dav_error * dav_fs_walk(dav_walker_ctx *wctx, int depth) { + const dav_walk_params *params = &wctx->w; dav_fs_walker_context fsctx = { 0 }; + dav_error *err; #if DAV_DEBUG - if ((wctx->walk_type & DAV_WALKTYPE_LOCKNULL) != 0 - && wctx->lockdb == NULL) { - return dav_new_error(wctx->pool, HTTP_INTERNAL_SERVER_ERROR, 0, + if ((params->walk_type & DAV_WALKTYPE_LOCKNULL) != 0 + && params->lockdb == NULL) { + return dav_new_error(params->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "DESIGN ERROR: walker called to walk locknull " "resources, but a lockdb was not provided."); } - - /* ### an assertion that we have space for a trailing slash */ - if (wctx->uri.cur_len + 1 > wctx->uri.alloc_len) { - return dav_new_error(wctx->pool, HTTP_INTERNAL_SERVER_ERROR, 0, - "DESIGN ERROR: walker should have been called " - "with padding in the URI buffer."); - } #endif - fsctx.wctx = wctx; - - wctx->root = wctx->resource; + fsctx.params = params; + fsctx.wres.walk_ctx = params->walk_ctx; /* ### zero out versioned, working, baselined? */ - fsctx.res1 = *wctx->resource; + fsctx.res1 = *params->root; fsctx.res1.info = &fsctx.info1; - fsctx.info1 = *wctx->resource->info; + fsctx.info1 = *params->root->info; - dav_buffer_init(wctx->pool, &fsctx.path1, fsctx.info1.pathname); + dav_buffer_init(params->pool, &fsctx.path1, fsctx.info1.pathname); fsctx.info1.pathname = fsctx.path1.buf; - if (wctx->res2 != NULL) { - fsctx.res2 = *wctx->res2; + if (params->root_dst != NULL) { + fsctx.res2 = *params->root_dst; fsctx.res2.exists = 0; fsctx.res2.collection = 0; fsctx.res2.info = &fsctx.info2; - fsctx.info2 = *wctx->res2->info; + fsctx.info2 = *params->root_dst->info; /* res2 does not exist -- clear its finfo structure */ memset(&fsctx.info2.finfo, 0, sizeof(fsctx.info2.finfo)); - dav_buffer_init(wctx->pool, &fsctx.path2, fsctx.info2.pathname); + dav_buffer_init(params->pool, &fsctx.path2, fsctx.info2.pathname); fsctx.info2.pathname = fsctx.path2.buf; } + /* prep the URI buffer */ + dav_buffer_init(params->pool, &fsctx.uri_buf, params->root->uri); + /* if we have a directory, then ensure the URI has a trailing "/" */ if (fsctx.res1.collection - && wctx->uri.buf[wctx->uri.cur_len - 1] != '/') { + && fsctx.uri_buf.buf[fsctx.uri_buf.cur_len - 1] != '/') { /* this will fall into the pad area */ - wctx->uri.buf[wctx->uri.cur_len++] = '/'; - wctx->uri.buf[wctx->uri.cur_len] = '\0'; + fsctx.uri_buf.buf[fsctx.uri_buf.cur_len++] = '/'; + fsctx.uri_buf.buf[fsctx.uri_buf.cur_len] = '\0'; } /* @@ -1587,14 +1598,16 @@ static dav_error * dav_fs_walk(dav_walker_ctx *wctx, int depth) ** to fetch it from res2. We will ensure that res1 and uri will remain ** synchronized. */ - fsctx.res1.uri = wctx->uri.buf; + fsctx.res1.uri = fsctx.uri_buf.buf; fsctx.res2.uri = NULL; /* use our resource structures */ - wctx->resource = &fsctx.res1; - wctx->res2 = &fsctx.res2; + fsctx.wres.resource = &fsctx.res1; + fsctx.wres.res_dst = &fsctx.res2; - return dav_fs_walker(&fsctx, depth); + err = dav_fs_walker(&fsctx, depth); + wctx->response = fsctx.wres.response; + return err; } /* dav_fs_etag: Stolen from ap_make_etag. Creates a strong etag diff --git a/modules/dav/main/mod_dav.c b/modules/dav/main/mod_dav.c index f01399a9a7..703036d5d9 100644 --- a/modules/dav/main/mod_dav.c +++ b/modules/dav/main/mod_dav.c @@ -1174,21 +1174,22 @@ static int dav_method_put(request_rec *r) } /* ### move this to dav_util? */ -DAV_DECLARE(void) dav_add_response(dav_walker_ctx *ctx, const char *href, +DAV_DECLARE(void) dav_add_response(dav_walk_resource *wres, int status, dav_get_props_result *propstats) { + dav_walker_ctx *ctx = wres->walk_ctx; dav_response *resp; /* just drop some data into an dav_response */ - resp = apr_pcalloc(ctx->pool, sizeof(*resp)); - resp->href = apr_pstrdup(ctx->pool, href); + resp = apr_pcalloc(ctx->w.pool, sizeof(*resp)); + resp->href = apr_pstrdup(ctx->w.pool, wres->resource->uri); resp->status = status; if (propstats) { resp->propresult = *propstats; } - resp->next = ctx->response; - ctx->response = resp; + resp->next = wres->response; + wres->response = resp; } /* handle the DELETE method */ @@ -1451,16 +1452,17 @@ static void dav_cache_badprops(dav_walker_ctx *ctx) return; } - ap_text_append(ctx->pool, &hdr, + ap_text_append(ctx->w.pool, &hdr, "" DEBUG_CR "" DEBUG_CR); elem = dav_find_child(ctx->doc->root, "prop"); for (elem = elem->first_child; elem; elem = elem->next) { - ap_text_append(ctx->pool, &hdr, ap_xml_empty_elem(ctx->pool, elem)); + ap_text_append(ctx->w.pool, &hdr, + ap_xml_empty_elem(ctx->w.pool, elem)); } - ap_text_append(ctx->pool, &hdr, + ap_text_append(ctx->w.pool, &hdr, "" DEBUG_CR "HTTP/1.1 404 Not Found" DEBUG_CR "" DEBUG_CR); @@ -1468,8 +1470,9 @@ static void dav_cache_badprops(dav_walker_ctx *ctx) ctx->propstat_404 = hdr.first; } -static dav_error * dav_propfind_walker(dav_walker_ctx *ctx, int calltype) +static dav_error * dav_propfind_walker(dav_walk_resource *wres, int calltype) { + dav_walker_ctx *ctx = wres->walk_ctx; dav_error *err; dav_propdb *propdb; dav_get_props_result propstats = { 0 }; @@ -1482,8 +1485,8 @@ static dav_error * dav_propfind_walker(dav_walker_ctx *ctx, int calltype) ** Note: we cast to lose the "const". The propdb won't try to change ** the resource, however, since we are opening readonly. */ - err = dav_open_propdb(ctx->r, ctx->lockdb, - (dav_resource *)ctx->resource, 1, + err = dav_open_propdb(ctx->r, ctx->w.lockdb, + (dav_resource *)wres->resource, 1, ctx->doc ? ctx->doc->namespaces : NULL, &propdb); if (err != NULL) { /* ### do something with err! */ @@ -1494,11 +1497,11 @@ static dav_error * dav_propfind_walker(dav_walker_ctx *ctx, int calltype) /* some props were expected on this collection/resource */ dav_cache_badprops(ctx); badprops.propstats = ctx->propstat_404; - dav_add_response(ctx, ctx->uri.buf, 0, &badprops); + dav_add_response(wres, 0, &badprops); } else { /* no props on this collection/resource */ - dav_add_response(ctx, ctx->uri.buf, HTTP_OK, NULL); + dav_add_response(wres, HTTP_OK, NULL); } return NULL; } @@ -1513,7 +1516,7 @@ static dav_error * dav_propfind_walker(dav_walker_ctx *ctx, int calltype) } dav_close_propdb(propdb); - dav_add_response(ctx, ctx->uri.buf, 0, &propstats); + dav_add_response(wres, 0, &propstats); return NULL; } @@ -1527,7 +1530,7 @@ static int dav_method_propfind(request_rec *r) int result; ap_xml_doc *doc; const ap_xml_elem *child; - dav_walker_ctx ctx = { 0 }; + dav_walker_ctx ctx = { { 0 } }; /* Ask repository module to resolve the resource */ result = dav_get_resource(r, 1 /*target_allowed*/, NULL, &resource); @@ -1596,17 +1599,17 @@ static int dav_method_propfind(request_rec *r) return HTTP_BAD_REQUEST; } - ctx.walk_type = DAV_WALKTYPE_ALL | DAV_WALKTYPE_AUTH; - ctx.func = dav_propfind_walker; - ctx.pool = r->pool; + ctx.w.walk_type = DAV_WALKTYPE_NORMAL | DAV_WALKTYPE_AUTH; + ctx.w.func = dav_propfind_walker; + ctx.w.walk_ctx = &ctx; + ctx.w.pool = r->pool; + ctx.w.root = resource; + ctx.doc = doc; ctx.r = r; - ctx.resource = resource; - - dav_buffer_init(r->pool, &ctx.uri, r->uri); /* ### should open read-only */ - if ((err = dav_open_lockdb(r, 0, &ctx.lockdb)) != NULL) { + if ((err = dav_open_lockdb(r, 0, &ctx.w.lockdb)) != NULL) { err = dav_push_error(r->pool, err->status, 0, "The lock database could not be opened, " "preventing access to the various lock " @@ -1614,15 +1617,15 @@ static int dav_method_propfind(request_rec *r) err); return dav_handle_err(r, err, NULL); } - if (ctx.lockdb != NULL) { + if (ctx.w.lockdb != NULL) { /* if we have a lock database, then we can walk locknull resources */ - ctx.walk_type |= DAV_WALKTYPE_LOCKNULL; + ctx.w.walk_type |= DAV_WALKTYPE_LOCKNULL; } err = (*resource->hooks->walk)(&ctx, depth); - if (ctx.lockdb != NULL) { - (*ctx.lockdb->hooks->close_lockdb)(ctx.lockdb); + if (ctx.w.lockdb != NULL) { + (*ctx.w.lockdb->hooks->close_lockdb)(ctx.w.lockdb); } if (err != NULL) { diff --git a/modules/dav/main/mod_dav.h b/modules/dav/main/mod_dav.h index ea65bd5cc8..daf2b5fd0b 100644 --- a/modules/dav/main/mod_dav.h +++ b/modules/dav/main/mod_dav.h @@ -1220,38 +1220,72 @@ void dav_prop_rollback(dav_prop_ctx *ctx); ** WALKER STRUCTURE */ -/* private, opaque info structure for repository walking context */ -typedef struct dav_walker_private dav_walker_private; +enum { + DAV_CALLTYPE_MEMBER = 1, /* called for a member resource */ + DAV_CALLTYPE_COLLECTION, /* called for a collection */ + DAV_CALLTYPE_LOCKNULL, /* called for a locknull resource */ + DAV_CALLTYPE_POSTFIX /* postfix call for a collection */ +}; -/* directory tree walking context */ -typedef struct dav_walker_ctx +typedef struct +{ + /* the client-provided context */ + void *walk_ctx; + + /* the current resource */ + const dav_resource *resource; + + /* the current secondary/tracking resource */ + const dav_resource *res_dst; + + /* OUTPUT: add responses to this */ + dav_response *response; + +} dav_walk_resource; + +typedef struct { int walk_type; -#define DAV_WALKTYPE_AUTH 1 /* limit to authorized files */ -#define DAV_WALKTYPE_ALL 2 /* walk normal files */ -#define DAV_WALKTYPE_HIDDEN 4 /* walk hidden files */ -#define DAV_WALKTYPE_LOCKNULL 8 /* walk locknull resources */ +#define DAV_WALKTYPE_AUTH 0x0001 /* limit to authorized files */ +#define DAV_WALKTYPE_NORMAL 0x0002 /* walk normal files */ +#define DAV_WALKTYPE_LOCKNULL 0x0004 /* walk locknull resources */ + +#define DAV_WALKTYPE_POSTFIX 0x0100 /* do postfix call for collections */ - int postfix; /* call func for dirs after files */ +#define DAV_WALKTYPE_ALL DAV_WALKTYPE_NORMAL /* ### compat */ +#define DAV_WALKTYPE_HIDDEN 0x1000 /* walk hidden files */ - dav_error * (*func)(struct dav_walker_ctx *ctx, int calltype); -#define DAV_CALLTYPE_MEMBER 1 /* called for a member resource */ -#define DAV_CALLTYPE_COLLECTION 2 /* called for a collection */ -#define DAV_CALLTYPE_LOCKNULL 3 /* called for a locknull resource */ -#define DAV_CALLTYPE_POSTFIX 4 /* postfix call for a collection */ + /* callback function and a client context for the walk */ + dav_error * (*func)(dav_walk_resource *wres, int calltype); + void *walk_ctx; + /* what pool to use for allocations needed by walk logic */ apr_pool_t *pool; - request_rec *r; /* original request */ - dav_buffer uri; /* current URI */ - const dav_resource *resource; /* current resource */ - const dav_resource *res2; /* optional secondary resource */ + /* beginning root of the walk */ + const dav_resource *root; - const dav_resource *root; /* RO: root resource of the walk */ + /* secondary, tracking resource */ + const dav_resource *root_dst; + /* lock database to enable walking LOCKNULL resources */ dav_lockdb *lockdb; - dav_response *response; /* OUT: multistatus responses */ +} dav_walk_params; + +/* directory tree walking context */ +typedef struct dav_walker_ctx +{ + /* input: */ + dav_walk_params w; + + /* output: */ + dav_response *response; + + + /* ### private data... phasing out this big glom */ + + request_rec *r; /* original request */ /* for PROPFIND operations */ ap_xml_doc *doc; @@ -1273,12 +1307,11 @@ typedef struct dav_walker_ctx int flags; - dav_walker_private *info; /* for use by repository manager */ - } dav_walker_ctx; -DAV_DECLARE(void) dav_add_response(dav_walker_ctx *ctx, const char *href, - int status, dav_get_props_result *propstats); +DAV_DECLARE(void) dav_add_response(dav_walk_resource *wres, + int status, + dav_get_props_result *propstats); /* -------------------------------------------------------------------- diff --git a/modules/dav/main/util.c b/modules/dav/main/util.c index 4ea01abfc9..00c0a0e63e 100644 --- a/modules/dav/main/util.c +++ b/modules/dav/main/util.c @@ -1184,12 +1184,13 @@ static dav_error * dav_validate_resource_state(apr_pool_t *p, } /* dav_validate_walker: Walker callback function to validate resource state */ -static dav_error * dav_validate_walker(dav_walker_ctx *ctx, int calltype) +static dav_error * dav_validate_walker(dav_walk_resource *wres, int calltype) { + dav_walker_ctx *ctx = wres->walk_ctx; dav_error *err; - if ((err = dav_validate_resource_state(ctx->pool, ctx->resource, - ctx->lockdb, + if ((err = dav_validate_resource_state(ctx->w.pool, wres->resource, + ctx->w.lockdb, ctx->if_header, ctx->flags, &ctx->work_buf, ctx->r)) == NULL) { /* There was no error, so just bug out. */ @@ -1201,14 +1202,14 @@ static dav_error * dav_validate_walker(dav_walker_ctx *ctx, int calltype) ** then just return error (not a multistatus). */ if (ap_is_HTTP_SERVER_ERROR(err->status) - || (*ctx->resource->hooks->is_same_resource)(ctx->resource, - ctx->root)) { + || (*wres->resource->hooks->is_same_resource)(wres->resource, + ctx->w.root)) { /* ### maybe push a higher-level description? */ return err; } /* associate the error with the current URI */ - dav_add_response(ctx, ctx->uri.buf, err->status, NULL); + dav_add_response(wres, err->status, NULL); return NULL; } @@ -1312,24 +1313,23 @@ dav_error * dav_validate_request(request_rec *r, dav_resource *resource, /* (1) Validate the specified resource, at the specified depth */ if (resource->exists && depth > 0) { - dav_walker_ctx ctx = { 0 }; + dav_walker_ctx ctx = { { 0 } }; + + ctx.w.walk_type = DAV_WALKTYPE_NORMAL; + ctx.w.func = dav_validate_walker; + ctx.w.walk_ctx = &ctx; + ctx.w.pool = r->pool; + ctx.w.root = resource; - ctx.walk_type = DAV_WALKTYPE_ALL; - ctx.postfix = 0; - ctx.func = dav_validate_walker; - ctx.pool = r->pool; ctx.if_header = if_header; ctx.r = r; ctx.flags = flags; - ctx.resource = resource; if (lockdb != NULL) { - ctx.lockdb = lockdb; - ctx.walk_type |= DAV_WALKTYPE_LOCKNULL; + ctx.w.lockdb = lockdb; + ctx.w.walk_type |= DAV_WALKTYPE_LOCKNULL; } - dav_buffer_init(r->pool, &ctx.uri, resource->uri); - err = (*repos_hooks->walk)(&ctx, DAV_INFINITY); if (err == NULL) { *response = ctx.response; diff --git a/modules/dav/main/util_lock.c b/modules/dav/main/util_lock.c index bdc1ab66c1..71c2ddf8ed 100644 --- a/modules/dav/main/util_lock.c +++ b/modules/dav/main/util_lock.c @@ -282,24 +282,26 @@ dav_error * dav_lock_parse_lockinfo(request_rec *r, */ /* dav_lock_walker: Walker callback function to record indirect locks */ -static dav_error * dav_lock_walker(dav_walker_ctx *ctx, int calltype) +static dav_error * dav_lock_walker(dav_walk_resource *wres, int calltype) { + dav_walker_ctx *ctx = wres->walk_ctx; dav_error *err; /* We don't want to set indirects on the target */ - if ((*ctx->resource->hooks->is_same_resource)(ctx->resource, ctx->root)) + if ((*wres->resource->hooks->is_same_resource)(wres->resource, + ctx->w.root)) return NULL; - if ((err = (*ctx->lockdb->hooks->append_locks)(ctx->lockdb, ctx->resource, - 1, - ctx->lock)) != NULL) { + if ((err = (*ctx->w.lockdb->hooks->append_locks)(ctx->w.lockdb, + wres->resource, 1, + ctx->lock)) != NULL) { if (ap_is_HTTP_SERVER_ERROR(err->status)) { /* ### add a higher-level description? */ return err; } /* add to the multistatus response */ - dav_add_response(ctx, ctx->resource->uri, err->status, NULL); + dav_add_response(wres, err->status, NULL); /* ** ### actually, this is probably wrong: we want to fail the whole @@ -353,19 +355,18 @@ dav_error * dav_add_lock(request_rec *r, const dav_resource *resource, if (depth > 0) { /* Walk existing collection and set indirect locks */ - dav_walker_ctx ctx = { 0 }; + dav_walker_ctx ctx = { { 0 } }; + + ctx.w.walk_type = DAV_WALKTYPE_ALL | DAV_WALKTYPE_AUTH; + ctx.w.func = dav_lock_walker; + ctx.w.walk_ctx = &ctx; + ctx.w.pool = r->pool; + ctx.w.root = resource; + ctx.w.lockdb = lockdb; - ctx.walk_type = DAV_WALKTYPE_ALL | DAV_WALKTYPE_AUTH; - ctx.postfix = 0; - ctx.func = dav_lock_walker; - ctx.pool = r->pool; ctx.r = r; - ctx.resource = resource; - ctx.lockdb = lockdb; ctx.lock = lock; - dav_buffer_init(r->pool, &ctx.uri, resource->uri); - err = (*resource->hooks->walk)(&ctx, DAV_INFINITY); if (err != NULL) { /* implies a 5xx status code occurred. screw the multistatus */ @@ -405,12 +406,14 @@ DAV_DECLARE(dav_error*) dav_lock_query(dav_lockdb *lockdb, } /* dav_unlock_walker: Walker callback function to remove indirect locks */ -static dav_error * dav_unlock_walker(dav_walker_ctx *ctx, int calltype) +static dav_error * dav_unlock_walker(dav_walk_resource *wres, int calltype) { + dav_walker_ctx *ctx = wres->walk_ctx; dav_error *err; - if ((err = (*ctx->lockdb->hooks->remove_lock)(ctx->lockdb, ctx->resource, - ctx->locktoken)) != NULL) { + if ((err = (*ctx->w.lockdb->hooks->remove_lock)(ctx->w.lockdb, + wres->resource, + ctx->locktoken)) != NULL) { /* ### should we stop or return a multistatus? looks like STOP */ /* ### add a higher-level description? */ return err; @@ -552,19 +555,18 @@ int dav_unlock(request_rec *r, const dav_resource *resource, } if (lock_resource->collection) { - dav_walker_ctx ctx = { 0 }; + dav_walker_ctx ctx = { { 0 } }; + + ctx.w.walk_type = DAV_WALKTYPE_NORMAL | DAV_WALKTYPE_LOCKNULL; + ctx.w.func = dav_unlock_walker; + ctx.w.walk_ctx = &ctx; + ctx.w.pool = r->pool; + ctx.w.root = lock_resource; + ctx.w.lockdb = lockdb; - ctx.walk_type = DAV_WALKTYPE_ALL | DAV_WALKTYPE_LOCKNULL; - ctx.postfix = 0; - ctx.func = dav_unlock_walker; - ctx.pool = r->pool; - ctx.resource = lock_resource; ctx.r = r; - ctx.lockdb = lockdb; ctx.locktoken = locktoken; - dav_buffer_init(r->pool, &ctx.uri, lock_resource->uri); - err = (*repos_hooks->walk)(&ctx, DAV_INFINITY); /* ### fix this! */ @@ -579,17 +581,20 @@ int dav_unlock(request_rec *r, const dav_resource *resource, } /* dav_inherit_walker: Walker callback function to inherit locks */ -static dav_error * dav_inherit_walker(dav_walker_ctx *ctx, int calltype) +static dav_error * dav_inherit_walker(dav_walk_resource *wres, int calltype) { + dav_walker_ctx *ctx = wres->walk_ctx; + if (ctx->skip_root - && (*ctx->resource->hooks->is_same_resource)(ctx->resource, - ctx->root)) { + && (*wres->resource->hooks->is_same_resource)(wres->resource, + ctx->w.root)) { return NULL; } /* ### maybe add a higher-level desc */ - return (*ctx->lockdb->hooks->append_locks)(ctx->lockdb, ctx->resource, 1, - ctx->lock); + return (*ctx->w.lockdb->hooks->append_locks)(ctx->w.lockdb, + wres->resource, 1, + ctx->lock); } /* @@ -607,7 +612,7 @@ static dav_error * dav_inherit_locks(request_rec *r, dav_lockdb *lockdb, dav_lock *locks; dav_lock *scan; dav_lock *prev; - dav_walker_ctx ctx = { 0 }; + dav_walker_ctx ctx = { { 0 } }; const dav_hooks_repository *repos_hooks = resource->hooks; if (use_parent) { @@ -661,18 +666,17 @@ static dav_error * dav_inherit_locks(request_rec *r, dav_lockdb *lockdb, /* has all our new locks. Walk down and propagate them. */ - ctx.walk_type = DAV_WALKTYPE_ALL | DAV_WALKTYPE_LOCKNULL; - ctx.postfix = 0; - ctx.func = dav_inherit_walker; - ctx.pool = r->pool; - ctx.resource = resource; + ctx.w.walk_type = DAV_WALKTYPE_NORMAL | DAV_WALKTYPE_LOCKNULL; + ctx.w.func = dav_inherit_walker; + ctx.w.walk_ctx = &ctx; + ctx.w.pool = r->pool; + ctx.w.root = resource; + ctx.w.lockdb = lockdb; + ctx.r = r; - ctx.lockdb = lockdb; ctx.lock = locks; ctx.skip_root = !use_parent; - dav_buffer_init(r->pool, &ctx.uri, resource->uri); - return (*repos_hooks->walk)(&ctx, DAV_INFINITY); } -- 2.50.1