summaryrefslogtreecommitdiff
path: root/subversion/mod_dav_svn/repos.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/mod_dav_svn/repos.c')
-rw-r--r--subversion/mod_dav_svn/repos.c862
1 files changed, 519 insertions, 343 deletions
diff --git a/subversion/mod_dav_svn/repos.c b/subversion/mod_dav_svn/repos.c
index 590cca9..9bf5ea0 100644
--- a/subversion/mod_dav_svn/repos.c
+++ b/subversion/mod_dav_svn/repos.c
@@ -56,6 +56,7 @@
#include "private/svn_log.h"
#include "private/svn_fspath.h"
#include "private/svn_repos_private.h"
+#include "private/svn_sorts_private.h"
#include "dav_svn.h"
@@ -899,7 +900,7 @@ prep_version(dav_resource_combined *comb)
comb->res.uri = dav_svn__build_uri(comb->priv.repos,
DAV_SVN__BUILD_URI_BASELINE,
comb->priv.root.rev, NULL,
- 0 /* add_href */,
+ FALSE /* add_href */,
pool);
return NULL;
@@ -1034,6 +1035,28 @@ prep_working(dav_resource_combined *comb)
comb->res.exists = (kind != svn_node_none);
comb->res.collection = (kind == svn_node_dir);
+ if (comb->res.exists
+ && comb->priv.r->method_number == M_MKCOL
+ && comb->priv.repos->is_svn_client)
+ {
+ /* mod_dav will now continue returning a generic HTTP_METHOD_NOT_ALLOWED
+ error, which doesn't produce nice output on SVN, nor gives any details
+ on why the operation failed.
+
+ Let's error out a bit earlier and produce an error message that is
+ easier to understand for both clients and users. */
+
+ /* It would be nice if we could error out a bit later (see issue #2295),
+ like in create_collection(), but mod_dav outsmarts us by just
+ returning the error when the node exists. */
+
+ return dav_svn__convert_err(
+ svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL,
+ "Path already exists, path '%s'",
+ comb->priv.repos_path),
+ HTTP_METHOD_NOT_ALLOWED, NULL, pool);
+ }
+
return NULL;
}
@@ -1168,7 +1191,7 @@ create_private_resource(const dav_resource *base,
if (base->info->repos->root_path[1])
comb->res.uri = apr_pstrcat(base->pool, base->info->repos->root_path,
- path->data, (char *)NULL);
+ path->data, SVN_VA_NULL);
else
comb->res.uri = path->data;
comb->res.info = &comb->priv;
@@ -1208,14 +1231,15 @@ static void log_warning(void *baton, svn_error_t *err)
AP_MODULE_DECLARE(dav_error *)
-dav_svn_split_uri(request_rec *r,
- const char *uri_to_split,
- const char *root_path,
- const char **cleaned_uri,
- int *trailing_slash,
- const char **repos_basename,
- const char **relative_path,
- const char **repos_path)
+dav_svn_split_uri2(request_rec *r,
+ const char *uri_to_split,
+ const char *root_path,
+ const char **cleaned_uri,
+ int *trailing_slash,
+ const char **repos_basename,
+ const char **relative_path,
+ const char **repos_path,
+ apr_pool_t *pool)
{
apr_size_t len1;
int had_slash;
@@ -1231,7 +1255,7 @@ dav_svn_split_uri(request_rec *r,
if ((fs_path == NULL) && (fs_parent_path == NULL))
{
/* ### are SVN_ERR_APMOD codes within the right numeric space? */
- return dav_svn__new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR,
+ return dav_svn__new_error(pool, HTTP_INTERNAL_SERVER_ERROR,
SVN_ERR_APMOD_MISSING_PATH_TO_FS,
"The server is misconfigured: "
"either an SVNPath or SVNParentPath "
@@ -1240,7 +1264,7 @@ dav_svn_split_uri(request_rec *r,
}
/* make a copy so that we can do some work on it */
- uri = apr_pstrdup(r->pool, uri_to_split);
+ uri = apr_pstrdup(pool, uri_to_split);
/* remove duplicate slashes, and make sure URI has no trailing '/' */
ap_no2slash(uri);
@@ -1255,7 +1279,7 @@ dav_svn_split_uri(request_rec *r,
*trailing_slash = FALSE;
/* return the first item. */
- *cleaned_uri = apr_pstrdup(r->pool, uri);
+ *cleaned_uri = apr_pstrdup(pool, uri);
/* The URL space defined by the SVN provider is always a virtual
space. Construct the path relative to the configured Location
@@ -1296,7 +1320,7 @@ dav_svn_split_uri(request_rec *r,
if (fs_path != NULL)
{
/* the repos_basename is the last component of root_path. */
- *repos_basename = svn_dirent_basename(root_path, r->pool);
+ *repos_basename = svn_dirent_basename(root_path, pool);
/* 'relative' is already correct for SVNPath; the root_path
already contains the name of the repository, so relative is
@@ -1314,7 +1338,7 @@ dav_svn_split_uri(request_rec *r,
if (relative[1] == '\0')
{
/* ### are SVN_ERR_APMOD codes within the right numeric space? */
- return dav_svn__new_error(r->pool, HTTP_FORBIDDEN,
+ return dav_svn__new_error(pool, HTTP_FORBIDDEN,
SVN_ERR_APMOD_MALFORMED_URI,
"The URI does not contain the name "
"of a repository.");
@@ -1331,7 +1355,7 @@ dav_svn_split_uri(request_rec *r,
}
else
{
- magic_component = apr_pstrndup(r->pool, relative + 1,
+ magic_component = apr_pstrndup(pool, relative + 1,
magic_end - relative - 1);
relative = magic_end;
}
@@ -1341,7 +1365,7 @@ dav_svn_split_uri(request_rec *r,
}
/* We can return 'relative' at this point too. */
- *relative_path = apr_pstrdup(r->pool, relative);
+ *relative_path = apr_pstrdup(pool, relative);
/* Code to remove the !svn junk from the front of the relative path,
mainly stolen from parse_uri(). This code assumes that
@@ -1362,7 +1386,7 @@ dav_svn_split_uri(request_rec *r,
if (ch == '\0')
{
/* relative is just "!svn", which is malformed. */
- return dav_svn__new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR,
+ return dav_svn__new_error(pool, HTTP_NOT_FOUND,
SVN_ERR_APMOD_MALFORMED_URI,
"Nothing follows the svn special_uri.");
}
@@ -1389,7 +1413,7 @@ dav_svn_split_uri(request_rec *r,
*repos_path = NULL;
else
return dav_svn__new_error(
- r->pool, HTTP_INTERNAL_SERVER_ERROR,
+ pool, HTTP_NOT_FOUND,
SVN_ERR_APMOD_MALFORMED_URI,
"Missing info after special_uri.");
}
@@ -1413,7 +1437,7 @@ dav_svn_split_uri(request_rec *r,
/* Did we break from the loop prematurely? */
if (j != (defn->numcomponents - 1))
return dav_svn__new_error(
- r->pool, HTTP_INTERNAL_SERVER_ERROR,
+ pool, HTTP_NOT_FOUND,
SVN_ERR_APMOD_MALFORMED_URI,
"Not enough components after "
"special_uri.");
@@ -1427,13 +1451,13 @@ dav_svn_split_uri(request_rec *r,
else
{
/* Found a slash after the special components. */
- *repos_path = apr_pstrdup(r->pool, start);
+ *repos_path = apr_pstrdup(pool, start - 1);
}
}
else
{
return
- dav_svn__new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR,
+ dav_svn__new_error(pool, HTTP_NOT_FOUND,
SVN_ERR_APMOD_MALFORMED_URI,
"Unknown data after special_uri.");
}
@@ -1444,7 +1468,7 @@ dav_svn_split_uri(request_rec *r,
if (defn->name == NULL)
return
- dav_svn__new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR,
+ dav_svn__new_error(pool, HTTP_NOT_FOUND,
SVN_ERR_APMOD_MALFORMED_URI,
"Couldn't match subdir after special_uri.");
}
@@ -1453,13 +1477,27 @@ dav_svn_split_uri(request_rec *r,
{
/* There's no "!svn/" at all, so the relative path is already
a valid path within the repository. */
- *repos_path = apr_pstrdup(r->pool, relative);
+ *repos_path = apr_pstrdup(pool, relative - 1);
}
}
return NULL;
}
+AP_MODULE_DECLARE(dav_error *)
+dav_svn_split_uri(request_rec *r,
+ const char *uri_to_split,
+ const char *root_path,
+ const char **cleaned_uri,
+ int *trailing_slash,
+ const char **repos_basename,
+ const char **relative_path,
+ const char **repos_path)
+{
+ return dav_svn_split_uri2(r, uri_to_split, root_path, cleaned_uri,
+ trailing_slash, repos_basename, relative_path,
+ repos_path, r->pool);
+}
/* Context for cleanup handler. */
struct cleanup_fs_access_baton
@@ -1530,7 +1568,7 @@ get_parentpath_resource(request_rec *r,
if (r->uri[len-1] != '/')
{
new_uri = apr_pstrcat(r->pool, ap_escape_uri(r->pool, r->uri),
- "/", (char *)NULL);
+ "/", SVN_VA_NULL);
apr_table_setn(r->headers_out, "Location",
ap_construct_url(r->pool, new_uri, r));
return dav_svn__new_error(r->pool, HTTP_MOVED_PERMANENTLY, 0,
@@ -1820,9 +1858,24 @@ do_out_of_date_check(dav_resource_combined *comb, request_rec *r)
"Attempting to modify out-of-date resource.",
r->pool);
}
+ else if (comb->priv.version_name > created_rev)
+ {
+ svn_revnum_t txn_base_rev;
+
+ txn_base_rev = svn_fs_txn_base_revision(comb->res.info->root.txn);
+ if (comb->priv.version_name > txn_base_rev)
+ {
+ serr = svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
+ "No such revision %ld",
+ comb->priv.version_name);
+
+ return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+ "Unknown base revision",
+ r->pool);
+ }
+ }
}
- else if (SVN_IS_VALID_REVNUM(comb->priv.version_name)
- && comb->res.collection)
+ else if (comb->res.collection)
{
/* Issue #4480: With HTTPv2 we can receive the first change for a
directory after it has been made mutable, because one of its
@@ -1837,7 +1890,7 @@ do_out_of_date_check(dav_resource_combined *comb, request_rec *r)
properties changed since the BASE version.
### I think svn_fs_node_relation() checks for more changes than we
- should check for here. Needs further review. But it looks like\
+ should check for here. Needs further review. But it looks like
this check matches the checks in the libsvn_fs commit editor.
For now I would say reporting out of date in a few too many
@@ -1846,8 +1899,7 @@ do_out_of_date_check(dav_resource_combined *comb, request_rec *r)
svn_revnum_t txn_base_rev;
svn_fs_root_t *txn_base_root;
svn_fs_root_t *rev_root;
- const svn_fs_id_t *txn_base_id;
- const svn_fs_id_t *rev_id;
+ svn_fs_node_relation_t node_relation;
txn_base_rev = svn_fs_txn_base_revision(comb->res.info->root.txn);
@@ -1856,15 +1908,11 @@ do_out_of_date_check(dav_resource_combined *comb, request_rec *r)
serr = svn_fs_revision_root(&txn_base_root, comb->res.info->repos->fs,
txn_base_rev, r->pool);
-
- if (!serr)
- serr = svn_fs_node_id(&txn_base_id, txn_base_root,
- comb->priv.repos_path, r->pool);
if (serr != NULL)
{
return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
- "Could not open youngest revision root "
+ "Could not open the transaction revision "
"for verification against the base "
"revision", r->pool);
}
@@ -1872,22 +1920,35 @@ do_out_of_date_check(dav_resource_combined *comb, request_rec *r)
serr = svn_fs_revision_root(&rev_root, comb->res.info->repos->fs,
comb->priv.version_name, r->pool);
- if (!serr)
- serr = svn_fs_node_id(&rev_id, rev_root,
- comb->priv.repos_path, r->pool);
-
if (serr != NULL)
{
+ svn_fs_close_root(txn_base_root);
return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
- "Could not open the base revision"
- "for verification against the youngest "
- "revision", r->pool);
+ "Could not open the base revision "
+ "for verification against the "
+ "transaction revision", r->pool);
}
+ serr = svn_fs_node_relation(&node_relation, rev_root,
+ comb->priv.repos_path,
+ txn_base_root,
+ comb->priv.repos_path,
+ r->pool);
+
svn_fs_close_root(rev_root);
svn_fs_close_root(txn_base_root);
- if (0 != svn_fs_compare_ids(txn_base_id, rev_id))
+ if (serr != NULL)
+ {
+ /* ### correct HTTP error? */
+ return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+ "Unable to fetch the node revision id "
+ "of the version resource within the "
+ "revision",
+ r->pool);
+ }
+
+ if (node_relation != svn_fs_node_unchanged)
{
serr = svn_error_createf(SVN_ERR_RA_OUT_OF_DATE, NULL,
"Directory '%s' is out of date",
@@ -2065,6 +2126,16 @@ get_resource(request_rec *r,
xslt_uri = dav_svn__get_xslt_uri(r);
fs_parent_path = dav_svn__get_fs_parent_path(r);
+ if (r->method_number == M_COPY)
+ {
+ /* Workaround for issue #4531: Avoid a depth-infinity walk on
+ the copy source by overriding the Depth header here.
+ mod_dav defaults to infinite depth if this header is not set
+ which makes copies O(size of source) rather than the desired O(1).
+ ### Should be fixed by an explicit provider API feature in mod_dav. */
+ apr_table_setn(r->headers_in, "Depth", "0");
+ }
+
/* Special case: detect and build the SVNParentPath as a unique type
of private resource, iff the SVNListParentPath directive is 'on'. */
if (dav_svn__is_parentpath_list(r))
@@ -2261,7 +2332,7 @@ get_resource(request_rec *r,
}
/* Retrieve/cache open repository */
- repos_key = apr_pstrcat(r->pool, "mod_dav_svn:", fs_path, (char *)NULL);
+ repos_key = apr_pstrcat(r->pool, "mod_dav_svn:", fs_path, SVN_VA_NULL);
apr_pool_userdata_get(&userdata, repos_key, r->connection->pool);
repos->repos = userdata;
if (repos->repos == NULL)
@@ -2275,7 +2346,9 @@ get_resource(request_rec *r,
svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_FULLTEXTS,
dav_svn__get_fulltext_cache_flag(r) ? "1" :"0");
svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_REVPROPS,
- dav_svn__get_revprop_cache_flag(r) ? "1" :"0");
+ dav_svn__get_revprop_cache_flag(r) ? "2" :"0");
+ svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_BLOCK_READ,
+ dav_svn__get_block_read_flag(r) ? "1" :"0");
/* Disallow BDB/event until issue 4157 is fixed. */
if (!strcmp(ap_show_mpm(), "event"))
@@ -2298,8 +2371,8 @@ get_resource(request_rec *r,
/* open the FS */
if (!serr)
- serr = svn_repos_open2(&(repos->repos), fs_path, fs_config,
- r->connection->pool);
+ serr = svn_repos_open3(&(repos->repos), fs_path, fs_config,
+ r->connection->pool, r->pool);
if (serr != NULL)
{
/* The error returned by svn_repos_open2 might contain the
@@ -2307,9 +2380,16 @@ get_resource(request_rec *r,
leak that path back to the client, because that would be
a security risk, but we do want to log the real error on
the server side. */
- return dav_svn__sanitize_error(serr, "Could not open the requested "
- "SVN filesystem",
- HTTP_INTERNAL_SERVER_ERROR, r);
+
+ apr_status_t cause = svn_error_root_cause(serr)->apr_err;
+ if (APR_STATUS_IS_ENOENT(cause) || APR_STATUS_IS_ENOTDIR(cause))
+ return dav_svn__sanitize_error(
+ serr, "Could not find the requested SVN filesystem",
+ HTTP_NOT_FOUND, r);
+ else
+ return dav_svn__sanitize_error(
+ serr, "Could not open the requested SVN filesystem",
+ HTTP_INTERNAL_SERVER_ERROR, r);
}
/* Cache the open repos for the next request on this connection */
@@ -2467,7 +2547,7 @@ get_resource(request_rec *r,
"/",
r->args ? "?" : "",
r->args ? r->args : "",
- (char *)NULL);
+ SVN_VA_NULL);
apr_table_setn(r->headers_out, "Location",
ap_construct_url(r->pool, new_path, r));
return dav_svn__new_error(r->pool, HTTP_MOVED_PERMANENTLY, 0,
@@ -3161,8 +3241,8 @@ set_headers(request_rec *r, const dav_resource *resource)
typedef struct diff_ctx_t {
- ap_filter_t *output;
- apr_pool_t *pool;
+ dav_svn__output *output;
+ apr_bucket_brigade *bb;
} diff_ctx_t;
@@ -3170,18 +3250,9 @@ static svn_error_t * __attribute__((warn_unused_result))
write_to_filter(void *baton, const char *buffer, apr_size_t *len)
{
diff_ctx_t *dc = baton;
- apr_bucket_brigade *bb;
- apr_bucket *bkt;
- apr_status_t status;
/* take the current data and shove it into the filter */
- bb = apr_brigade_create(dc->pool, dc->output->c->bucket_alloc);
- bkt = apr_bucket_transient_create(buffer, *len, dc->output->c->bucket_alloc);
- APR_BRIGADE_INSERT_TAIL(bb, bkt);
- if ((status = ap_pass_brigade(dc->output, bb)) != APR_SUCCESS) {
- return svn_error_create(status, NULL,
- "Could not write data to filter");
- }
+ SVN_ERR(dav_svn__brigade_write(dc->bb, dc->output, buffer, *len));
return SVN_NO_ERROR;
}
@@ -3191,28 +3262,270 @@ static svn_error_t * __attribute__((warn_unused_result))
close_filter(void *baton)
{
diff_ctx_t *dc = baton;
- apr_bucket_brigade *bb;
apr_bucket *bkt;
- apr_status_t status;
/* done with the file. write an EOS bucket now. */
- bb = apr_brigade_create(dc->pool, dc->output->c->bucket_alloc);
- bkt = apr_bucket_eos_create(dc->output->c->bucket_alloc);
- APR_BRIGADE_INSERT_TAIL(bb, bkt);
- if ((status = ap_pass_brigade(dc->output, bb)) != APR_SUCCESS)
- return svn_error_create(status, NULL, "Could not write EOS to filter");
+ bkt = apr_bucket_eos_create(dav_svn__output_get_bucket_alloc(dc->output));
+ APR_BRIGADE_INSERT_TAIL(dc->bb, bkt);
+ SVN_ERR(dav_svn__output_pass_brigade(dc->output, dc->bb));
+
+ return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+emit_collection_head(const dav_resource *resource,
+ apr_bucket_brigade *bb,
+ dav_svn__output *output,
+ svn_boolean_t gen_html,
+ apr_pool_t *pool)
+{
+ /* XML schema for the directory index if xslt_uri is set:
+
+ <?xml version="1.0"?>
+ <?xml-stylesheet type="text/xsl" href="[info->repos->xslt_uri]"?> */
+ static const char xml_index_dtd[] =
+ "<!DOCTYPE svn [\n"
+ " <!ELEMENT svn (index)>\n"
+ " <!ATTLIST svn version CDATA #REQUIRED\n"
+ " href CDATA #REQUIRED>\n"
+ " <!ELEMENT index (updir?, (file | dir)*)>\n"
+ " <!ATTLIST index name CDATA #IMPLIED\n"
+ " path CDATA #IMPLIED\n"
+ " rev CDATA #IMPLIED\n"
+ " base CDATA #IMPLIED>\n"
+ " <!ELEMENT updir EMPTY>\n"
+ " <!ATTLIST updir href CDATA #REQUIRED>\n"
+ " <!ELEMENT file EMPTY>\n"
+ " <!ATTLIST file name CDATA #REQUIRED\n"
+ " href CDATA #REQUIRED>\n"
+ " <!ELEMENT dir EMPTY>\n"
+ " <!ATTLIST dir name CDATA #REQUIRED\n"
+ " href CDATA #REQUIRED>\n"
+ "]>\n";
+
+ if (gen_html)
+ {
+ const char *title;
+ if (resource->info->repos_path == NULL)
+ title = "unknown location";
+ else
+ title = resource->info->repos_path;
+
+ if (resource->info->restype != DAV_SVN_RESTYPE_PARENTPATH_COLLECTION)
+ {
+ if (SVN_IS_VALID_REVNUM(resource->info->root.rev))
+ title = apr_psprintf(pool,
+ "Revision %ld: %s",
+ resource->info->root.rev, title);
+ if (resource->info->repos->repo_basename)
+ title = apr_psprintf(pool, "%s - %s",
+ resource->info->repos->repo_basename,
+ title);
+ if (resource->info->repos->repo_name)
+ title = apr_psprintf(pool, "%s: %s",
+ resource->info->repos->repo_name,
+ title);
+ }
+
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
+ "<html><head><title>%s</title></head>\n"
+ "<body>\n <h2>%s</h2>\n <ul>\n",
+ title, title));
+ }
+ else
+ {
+ const char *name = resource->info->repos->repo_name;
+ const char *href = resource->info->repos_path;
+ const char *base = resource->info->repos->repo_basename;
+
+ SVN_ERR(dav_svn__brigade_puts(bb, output, "<?xml version=\"1.0\"?>\n"));
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
+ "<?xml-stylesheet type=\"text/xsl\" "
+ "href=\"%s\"?>\n",
+ resource->info->repos->xslt_uri));
+ SVN_ERR(dav_svn__brigade_puts(bb, output, xml_index_dtd));
+ SVN_ERR(dav_svn__brigade_puts(bb, output,
+ "<svn version=\"" SVN_VERSION "\"\n"
+ " href=\"http://subversion.apache.org/\">\n"));
+ SVN_ERR(dav_svn__brigade_puts(bb, output, " <index"));
+
+ if (name)
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
+ " name=\"%s\"",
+ apr_xml_quote_string(resource->pool,
+ name, 1)));
+ if (SVN_IS_VALID_REVNUM(resource->info->root.rev))
+ SVN_ERR(dav_svn__brigade_printf(bb, output, " rev=\"%ld\"",
+ resource->info->root.rev));
+ if (href)
+ SVN_ERR(dav_svn__brigade_printf(bb, output, " path=\"%s\"",
+ apr_xml_quote_string(resource->pool,
+ href, 1)));
+ if (base)
+ SVN_ERR(dav_svn__brigade_printf(bb, output, " base=\"%s\"", base));
+
+ SVN_ERR(dav_svn__brigade_puts(bb, output, ">\n"));
+ }
+
+ if ((resource->info->restype != DAV_SVN_RESTYPE_PARENTPATH_COLLECTION)
+ && resource->info->repos_path
+ && ((resource->info->repos_path[1] != '\0')
+ || dav_svn__get_list_parentpath_flag(resource->info->r)))
+ {
+ const char *href;
+ if (resource->info->pegged)
+ {
+ href = apr_psprintf(pool, "../?p=%ld", resource->info->root.rev);
+ }
+ else
+ {
+ href = "../";
+ }
+
+ if (gen_html)
+ {
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
+ " <li><a href=\"%s\">..</a></li>\n",
+ href));
+ }
+ else
+ {
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
+ " <updir href=\"%s\"/>\n",
+ href));
+ }
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+emit_collection_entry(const dav_resource *resource,
+ apr_bucket_brigade *bb,
+ dav_svn__output *output,
+ const svn_fs_dirent_t *entry,
+ svn_boolean_t gen_html,
+ apr_pool_t *pool)
+{
+ const char *name = entry->name;
+ const char *href = name;
+ svn_boolean_t is_dir = (entry->kind == svn_node_dir);
+
+ /* append a trailing slash onto the name for directories. we NEED
+ this for the href portion so that the relative reference will
+ descend properly. for the visible portion, it is just nice. */
+ /* ### The xml output doesn't like to see a trailing slash on
+ ### the visible portion, so avoid that. */
+ if (is_dir)
+ href = apr_pstrcat(pool, href, "/", SVN_VA_NULL);
+
+ if (gen_html)
+ name = href;
+
+ /* We quote special characters in both XML and HTML. */
+ name = apr_xml_quote_string(pool, name, !gen_html);
+
+ /* According to httpd-2.0.54/include/httpd.h, ap_os_escape_path()
+ behaves differently on different platforms. It claims to
+ "convert an OS path to a URL in an OS dependant way".
+ Nevertheless, there appears to be only one implementation
+ of the function in httpd, and the code seems completely
+ platform independent, so we'll assume it's appropriate for
+ mod_dav_svn to use it to quote outbound paths. */
+ href = ap_os_escape_path(pool, href, 0);
+ href = apr_xml_quote_string(pool, href, 1);
+
+ if (gen_html)
+ {
+ /* If our directory was access using the public peg-rev
+ CGI query interface, we'll let its dirents carry that
+ peg-rev, too. */
+ if (resource->info->pegged)
+ {
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
+ " <li><a href=\"%s?p=%ld\">%s</a></li>\n",
+ href, resource->info->root.rev, name));
+ }
+ else
+ {
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
+ " <li><a href=\"%s\">%s</a></li>\n",
+ href, name));
+ }
+ }
+ else
+ {
+ const char *const tag = (is_dir ? "dir" : "file");
+
+ /* This is where we could search for props */
+
+ /* If our directory was access using the public peg-rev
+ CGI query interface, we'll let its dirents carry that
+ peg-rev, too. */
+ if (resource->info->pegged)
+ {
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
+ " <%s name=\"%s\" href=\"%s?p=%ld\" />\n",
+ tag, name, href, resource->info->root.rev));
+ }
+ else
+ {
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
+ " <%s name=\"%s\" href=\"%s\" />\n",
+ tag, name, href));
+ }
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+emit_collection_tail(const dav_resource *resource,
+ apr_bucket_brigade *bb,
+ dav_svn__output *output,
+ svn_boolean_t gen_html,
+ apr_pool_t *pool)
+{
+ if (gen_html)
+ {
+ if (strcmp(ap_psignature("FOO", resource->info->r), "") != 0)
+ {
+ /* Apache's signature generation code didn't eat our prefix.
+ ServerSignature must be enabled. Print our version info.
+
+ WARNING: This is a kludge!! ap_psignature() doesn't promise
+ to return the empty string when ServerSignature is off. We
+ know it does by code inspection, but this behavior is subject
+ to change. (Perhaps we should try to get the Apache folks to
+ make this promise, though. Seems harmless/useful enough...)
+ */
+ SVN_ERR(dav_svn__brigade_puts(bb, output,
+ " </ul>\n <hr noshade><em>Powered by "
+ "<a href=\"http://subversion.apache.org/\">"
+ "Apache Subversion"
+ "</a> version " SVN_VERSION "."
+ "</em>\n</body></html>"));
+ }
+ else
+ SVN_ERR(dav_svn__brigade_puts(bb, output, " </ul>\n</body></html>"));
+ }
+ else
+ SVN_ERR(dav_svn__brigade_puts(bb, output, " </index>\n</svn>\n"));
return SVN_NO_ERROR;
}
static dav_error *
-deliver(const dav_resource *resource, ap_filter_t *output)
+deliver(const dav_resource *resource, ap_filter_t *unused)
{
svn_error_t *serr;
apr_bucket_brigade *bb;
apr_bucket *bkt;
- apr_status_t status;
+ dav_svn__output *output;
/* Check resource type */
if (resource->baselined
@@ -3225,39 +3538,17 @@ deliver(const dav_resource *resource, ap_filter_t *output)
"Cannot GET this type of resource.");
}
+ output = dav_svn__output_create(resource->info->r, resource->pool);
+
if (resource->collection)
{
const int gen_html = !resource->info->repos->xslt_uri;
apr_hash_t *entries;
- apr_pool_t *entry_pool;
+ apr_pool_t *iterpool;
apr_array_header_t *sorted;
svn_revnum_t dir_rev = SVN_INVALID_REVNUM;
int i;
- /* XML schema for the directory index if xslt_uri is set:
-
- <?xml version="1.0"?>
- <?xml-stylesheet type="text/xsl" href="[info->repos->xslt_uri]"?> */
- static const char xml_index_dtd[] =
- "<!DOCTYPE svn [\n"
- " <!ELEMENT svn (index)>\n"
- " <!ATTLIST svn version CDATA #REQUIRED\n"
- " href CDATA #REQUIRED>\n"
- " <!ELEMENT index (updir?, (file | dir)*)>\n"
- " <!ATTLIST index name CDATA #IMPLIED\n"
- " path CDATA #IMPLIED\n"
- " rev CDATA #IMPLIED\n"
- " base CDATA #IMPLIED>\n"
- " <!ELEMENT updir EMPTY>\n"
- " <!ATTLIST updir href CDATA #REQUIRED>\n"
- " <!ELEMENT file EMPTY>\n"
- " <!ATTLIST file name CDATA #REQUIRED\n"
- " href CDATA #REQUIRED>\n"
- " <!ELEMENT dir EMPTY>\n"
- " <!ATTLIST dir name CDATA #REQUIRED\n"
- " href CDATA #REQUIRED>\n"
- "]>\n";
-
/* <svn version="1.3.0 (dev-build)"
href="http://subversion.apache.org">
<index name="[info->repos->repo_name]"
@@ -3338,99 +3629,21 @@ deliver(const dav_resource *resource, ap_filter_t *output)
resource->pool);
}
- bb = apr_brigade_create(resource->pool, output->c->bucket_alloc);
-
- if (gen_html)
- {
- const char *title;
- if (resource->info->repos_path == NULL)
- title = "unknown location";
- else
- title = resource->info->repos_path;
-
- if (resource->info->restype != DAV_SVN_RESTYPE_PARENTPATH_COLLECTION)
- {
- if (SVN_IS_VALID_REVNUM(resource->info->root.rev))
- title = apr_psprintf(resource->pool,
- "Revision %ld: %s",
- resource->info->root.rev, title);
- if (resource->info->repos->repo_basename)
- title = apr_psprintf(resource->pool, "%s - %s",
- resource->info->repos->repo_basename,
- title);
- if (resource->info->repos->repo_name)
- title = apr_psprintf(resource->pool, "%s: %s",
- resource->info->repos->repo_name,
- title);
- }
-
- ap_fprintf(output, bb, "<html><head><title>%s</title></head>\n"
- "<body>\n <h2>%s</h2>\n <ul>\n", title, title);
- }
- else
- {
- const char *name = resource->info->repos->repo_name;
- const char *href = resource->info->repos_path;
- const char *base = resource->info->repos->repo_basename;
-
- ap_fputs(output, bb, "<?xml version=\"1.0\"?>\n");
- ap_fprintf(output, bb,
- "<?xml-stylesheet type=\"text/xsl\" href=\"%s\"?>\n",
- resource->info->repos->xslt_uri);
- ap_fputs(output, bb, xml_index_dtd);
- ap_fputs(output, bb,
- "<svn version=\"" SVN_VERSION "\"\n"
- " href=\"http://subversion.apache.org/\">\n");
- ap_fputs(output, bb, " <index");
- if (name)
- ap_fprintf(output, bb, " name=\"%s\"",
- apr_xml_quote_string(resource->pool, name, 1));
- if (SVN_IS_VALID_REVNUM(resource->info->root.rev))
- ap_fprintf(output, bb, " rev=\"%ld\"",
- resource->info->root.rev);
- if (href)
- ap_fprintf(output, bb, " path=\"%s\"",
- apr_xml_quote_string(resource->pool,
- href,
- 1));
- if (base)
- ap_fprintf(output, bb, " base=\"%s\"", base);
-
- ap_fputs(output, bb, ">\n");
- }
-
- if ((resource->info->restype != DAV_SVN_RESTYPE_PARENTPATH_COLLECTION)
- && resource->info->repos_path
- && ((resource->info->repos_path[1] != '\0')
- || dav_svn__get_list_parentpath_flag(resource->info->r)))
- {
- const char *href;
- if (resource->info->pegged)
- {
- href = apr_psprintf(resource->pool, "../?p=%ld",
- resource->info->root.rev);
- }
- else
- {
- href = "../";
- }
+ bb = apr_brigade_create(resource->pool,
+ dav_svn__output_get_bucket_alloc(output));
- if (gen_html)
- {
- ap_fprintf(output, bb,
- " <li><a href=\"%s\">..</a></li>\n", href);
- }
- else
- {
- ap_fprintf(output, bb, " <updir href=\"%s\"/>\n", href);
- }
- }
+ serr = emit_collection_head(resource, bb, output, gen_html,
+ resource->pool);
+ if (serr != NULL)
+ return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+ "could not output collection",
+ resource->pool);
/* get a sorted list of the entries */
sorted = svn_sort__hash(entries, svn_sort_compare_items_as_paths,
resource->pool);
- entry_pool = svn_pool_create(resource->pool);
+ iterpool = svn_pool_create(resource->pool);
for (i = 0; i < sorted->nelts; ++i)
{
@@ -3438,11 +3651,9 @@ deliver(const dav_resource *resource, ap_filter_t *output)
const svn_sort__item_t);
const svn_fs_dirent_t *entry = item->value;
const char *name = item->key;
- const char *href = name;
- svn_boolean_t is_dir = (entry->kind == svn_node_dir);
const char *repos_relpath = NULL;
- svn_pool_clear(entry_pool);
+ svn_pool_clear(iterpool);
/* DIR_REV is set to a valid revision if we're looking at
the entries of a versioned directory. Otherwise, we're
@@ -3450,120 +3661,45 @@ deliver(const dav_resource *resource, ap_filter_t *output)
if (SVN_IS_VALID_REVNUM(dir_rev))
{
repos_relpath = svn_fspath__join(resource->info->repos_path,
- name, entry_pool);
+ name, iterpool);
if (! dav_svn__allow_read(resource->info->r,
resource->info->repos,
repos_relpath,
dir_rev,
- entry_pool))
+ iterpool))
continue;
}
else
{
if (! dav_svn__allow_list_repos(resource->info->r,
- entry->name, entry_pool))
+ entry->name, iterpool))
continue;
}
- /* append a trailing slash onto the name for directories. we NEED
- this for the href portion so that the relative reference will
- descend properly. for the visible portion, it is just nice. */
- /* ### The xml output doesn't like to see a trailing slash on
- ### the visible portion, so avoid that. */
- if (is_dir)
- href = apr_pstrcat(entry_pool, href, "/", (char *)NULL);
-
- if (gen_html)
- name = href;
-
- /* We quote special characters in both XML and HTML. */
- name = apr_xml_quote_string(entry_pool, name, !gen_html);
-
- /* According to httpd-2.0.54/include/httpd.h, ap_os_escape_path()
- behaves differently on different platforms. It claims to
- "convert an OS path to a URL in an OS dependant way".
- Nevertheless, there appears to be only one implementation
- of the function in httpd, and the code seems completely
- platform independent, so we'll assume it's appropriate for
- mod_dav_svn to use it to quote outbound paths. */
- href = ap_os_escape_path(entry_pool, href, 0);
- href = apr_xml_quote_string(entry_pool, href, 1);
-
- if (gen_html)
- {
- /* If our directory was access using the public peg-rev
- CGI query interface, we'll let its dirents carry that
- peg-rev, too. */
- if (resource->info->pegged)
- {
- ap_fprintf(output, bb,
- " <li><a href=\"%s?p=%ld\">%s</a></li>\n",
- href, resource->info->root.rev, name);
- }
- else
- {
- ap_fprintf(output, bb,
- " <li><a href=\"%s\">%s</a></li>\n",
- href, name);
- }
- }
- else
- {
- const char *const tag = (is_dir ? "dir" : "file");
-
- /* This is where we could search for props */
-
- /* If our directory was access using the public peg-rev
- CGI query interface, we'll let its dirents carry that
- peg-rev, too. */
- if (resource->info->pegged)
- {
- ap_fprintf(output, bb,
- " <%s name=\"%s\" href=\"%s?p=%ld\" />\n",
- tag, name, href, resource->info->root.rev);
- }
- else
- {
- ap_fprintf(output, bb,
- " <%s name=\"%s\" href=\"%s\" />\n",
- tag, name, href);
- }
- }
+ serr = emit_collection_entry(resource, bb, output, entry, gen_html,
+ iterpool);
+ if (serr != NULL)
+ return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+ "could not output collection entry",
+ resource->pool);
}
- svn_pool_destroy(entry_pool);
+ svn_pool_destroy(iterpool);
- if (gen_html)
- {
- if (strcmp(ap_psignature("FOO", resource->info->r), "") != 0)
- {
- /* Apache's signature generation code didn't eat our prefix.
- ServerSignature must be enabled. Print our version info.
-
- WARNING: This is a kludge!! ap_psignature() doesn't promise
- to return the empty string when ServerSignature is off. We
- know it does by code inspection, but this behavior is subject
- to change. (Perhaps we should try to get the Apache folks to
- make this promise, though. Seems harmless/useful enough...)
- */
- ap_fputs(output, bb,
- " </ul>\n <hr noshade><em>Powered by "
- "<a href=\"http://subversion.apache.org/\">"
- "Apache Subversion"
- "</a> version " SVN_VERSION "."
- "</em>\n</body></html>");
- }
- else
- ap_fputs(output, bb, " </ul>\n</body></html>");
- }
- else
- ap_fputs(output, bb, " </index>\n</svn>\n");
+ serr = emit_collection_tail(resource, bb, output, gen_html,
+ resource->pool);
+ if (serr != NULL)
+ return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+ "could not output collection",
+ resource->pool);
- bkt = apr_bucket_eos_create(output->c->bucket_alloc);
+ bkt = apr_bucket_eos_create(dav_svn__output_get_bucket_alloc(output));
APR_BRIGADE_INSERT_TAIL(bb, bkt);
- if ((status = ap_pass_brigade(output, bb)) != APR_SUCCESS)
- return dav_svn__new_error(resource->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
- "Could not write EOS to filter.");
+ serr = dav_svn__output_pass_brigade(output, bb);
+ if (serr != NULL)
+ return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+ "Could not write EOS to filter.",
+ resource->pool);
return NULL;
}
@@ -3626,10 +3762,13 @@ deliver(const dav_resource *resource, ap_filter_t *output)
"could not prepare to read a delta",
resource->pool);
+ bb = apr_brigade_create(resource->pool,
+ dav_svn__output_get_bucket_alloc(output));
+
/* create a stream that svndiff data will be written to,
which will copy it to the network */
dc.output = output;
- dc.pool = resource->pool;
+ dc.bb = bb;
o_stream = svn_stream_create(&dc, resource->pool);
svn_stream_set_write(o_stream, write_to_filter);
svn_stream_set_close(o_stream, close_filter);
@@ -3645,6 +3784,8 @@ deliver(const dav_resource *resource, ap_filter_t *output)
to the network. */
serr = svn_txdelta_send_txstream(txd_stream, handler, h_baton,
resource->pool);
+ apr_brigade_destroy(bb);
+
if (serr != NULL)
return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
"could not deliver the txdelta stream",
@@ -3723,11 +3864,11 @@ deliver(const dav_resource *resource, ap_filter_t *output)
resource->info->repos->base_url,
ap_escape_uri(resource->pool,
resource->info->r->uri),
- NULL);
+ SVN_VA_NULL);
str_root = apr_pstrcat(resource->pool,
resource->info->repos->base_url,
resource->info->repos->root_path,
- NULL);
+ SVN_VA_NULL);
serr = svn_subst_build_keywords3(&kw, keywords->data,
str_cmt_rev, str_uri, str_root,
@@ -3750,13 +3891,17 @@ deliver(const dav_resource *resource, ap_filter_t *output)
### which will read from the FS stream on demand */
block = apr_palloc(resource->pool, SVN__STREAM_CHUNK_SIZE);
+ bb = apr_brigade_create(resource->pool,
+ dav_svn__output_get_bucket_alloc(output));
+
while (1) {
apr_size_t bufsize = SVN__STREAM_CHUNK_SIZE;
/* read from the FS ... */
- serr = svn_stream_read(stream, block, &bufsize);
+ serr = svn_stream_read_full(stream, block, &bufsize);
if (serr != NULL)
{
+ apr_brigade_destroy(bb);
return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
"could not read the file contents",
resource->pool);
@@ -3764,30 +3909,35 @@ deliver(const dav_resource *resource, ap_filter_t *output)
if (bufsize == 0)
break;
- /* build a brigade and write to the filter ... */
- bb = apr_brigade_create(resource->pool, output->c->bucket_alloc);
- bkt = apr_bucket_transient_create(block, bufsize,
- output->c->bucket_alloc);
+ /* write to the filter ... */
+ bkt = apr_bucket_transient_create(
+ block, bufsize, dav_svn__output_get_bucket_alloc(output));
APR_BRIGADE_INSERT_TAIL(bb, bkt);
- if ((status = ap_pass_brigade(output, bb)) != APR_SUCCESS) {
- /* ### what to do with status; and that HTTP code... */
- return dav_svn__new_error(resource->pool,
- HTTP_INTERNAL_SERVER_ERROR, 0,
- "Could not write data to filter.");
- }
+ serr = dav_svn__output_pass_brigade(output, bb);
+ if (serr != NULL)
+ {
+ apr_brigade_destroy(bb);
+ /* ### that HTTP code... */
+ return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+ "Could not write data to filter.",
+ resource->pool);
+ }
}
/* done with the file. write an EOS bucket now. */
- bb = apr_brigade_create(resource->pool, output->c->bucket_alloc);
- bkt = apr_bucket_eos_create(output->c->bucket_alloc);
+ bkt = apr_bucket_eos_create(dav_svn__output_get_bucket_alloc(output));
APR_BRIGADE_INSERT_TAIL(bb, bkt);
- if ((status = ap_pass_brigade(output, bb)) != APR_SUCCESS) {
- /* ### what to do with status; and that HTTP code... */
- return dav_svn__new_error(resource->pool,
- HTTP_INTERNAL_SERVER_ERROR, 0,
- "Could not write EOS to filter.");
- }
+ serr = dav_svn__output_pass_brigade(output, bb);
+ if (serr != NULL)
+ {
+ apr_brigade_destroy(bb);
+ /* ### that HTTP code... */
+ return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+ "Could not write EOS to filter.",
+ resource->pool);
+ }
+ apr_brigade_destroy(bb);
return NULL;
}
}
@@ -3904,23 +4054,28 @@ copy_resource(const dav_resource *src,
return err;
}
- serr = svn_dirent_get_absolute(&src_repos_path,
- svn_repos_path(src->info->repos->repos,
- src->pool),
- src->pool);
- if (!serr)
- serr = svn_dirent_get_absolute(&dst_repos_path,
- svn_repos_path(dst->info->repos->repos,
- dst->pool),
- dst->pool);
+ src_repos_path = svn_repos_path(src->info->repos->repos, src->pool);
+ dst_repos_path = svn_repos_path(dst->info->repos->repos, dst->pool);
+
+ if (strcmp(src_repos_path, dst_repos_path) != 0)
+ {
+ /* Perhaps the source and dst repos use different path formats? */
+ serr = svn_error_compose_create(
+ svn_dirent_get_absolute(&src_repos_path, src_repos_path,
+ src->pool),
+ svn_dirent_get_absolute(&dst_repos_path, dst_repos_path,
+ dst->pool));
+
+ if (!serr && (strcmp(src_repos_path, dst_repos_path) != 0))
+ return dav_svn__new_error_svn(
+ dst->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
+ "Copy source and destination are in different repositories");
+ }
+ else
+ serr = SVN_NO_ERROR;
if (!serr)
{
- if (strcmp(src_repos_path, dst_repos_path) != 0)
- return dav_svn__new_error_tag
- (dst->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
- "Copy source and destination are in different repositories.",
- SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG);
serr = svn_fs_copy(src->info->root.root, /* root object of src rev*/
src->info->repos_path, /* relative path of src */
dst->info->root.root, /* root object of dst txn*/
@@ -4030,7 +4185,11 @@ remove_resource(dav_resource *resource, dav_response **response)
if (resource->info->version_name < created_rev)
{
serr = svn_error_createf(SVN_ERR_RA_OUT_OF_DATE, NULL,
- "Item '%s' is out of date",
+ resource->collection
+ ? "Directory '%s' is out of date"
+ : (resource->exists
+ ? "File '%s' is out of date"
+ : "'%s' is out of date"),
resource->info->repos_path);
return dav_svn__convert_err(serr, HTTP_CONFLICT,
"Can't DELETE out-of-date resource",
@@ -4042,8 +4201,9 @@ remove_resource(dav_resource *resource, dav_response **response)
incoming lock-tokens into the filesystem's access_t. Normally
they come in via 'If:' header, and get_resource()
automatically notices them and does this work for us. In the
- case of a directory deletion, however, svn clients are sending
- 'child' lock-tokens in the DELETE request body. */
+ case of a directory deletion, however, older subversion clients
+ are sending 'child' lock-tokens in the non-standard DELETE
+ request body. */
err = dav_svn__build_lock_hash(&locks, resource->info->r,
resource->info->repos_path, resource->pool);
@@ -4157,10 +4317,15 @@ typedef struct walker_ctx_t {
} walker_ctx_t;
-
+/* Recursively walk a resource for walk(). When DEPTH != 0, recurse with
+ DEPTH-1 on child nodes. WALK_ROOT should be TRUE for the root and will be
+ FALSE for any descendants, to avoid unneeded work for every descendant
+ node.
+ */
static dav_error *
do_walk(walker_ctx_t *ctx,
int depth,
+ svn_boolean_t walk_root,
apr_pool_t *scratch_pool)
{
const dav_walk_params *params = ctx->params;
@@ -4225,16 +4390,19 @@ do_walk(walker_ctx_t *ctx,
uri_len = ctx->uri->len;
repos_len = ctx->repos_path->len;
- /* Tell our logging subsystem that we're listing a directory.
-
- Note: if we cared, we could look at the 'User-Agent:' request
- header and distinguish an svn client ('svn ls') from a generic
- DAV client. */
- dav_svn__operational_log(&ctx->info,
- svn_log__get_dir(ctx->info.repos_path,
- ctx->info.root.rev,
- TRUE, FALSE, SVN_DIRENT_ALL,
- scratch_pool));
+ if (walk_root)
+ {
+ /* Tell our logging subsystem that we're listing a directory.
+
+ Note: if we cared, we could look at the 'User-Agent:' request
+ header and distinguish an svn client ('svn ls') from a generic
+ DAV client. */
+ dav_svn__operational_log(&ctx->info,
+ svn_log__get_dir(ctx->info.repos_path,
+ ctx->info.root.rev,
+ TRUE, FALSE, SVN_DIRENT_ALL,
+ scratch_pool));
+ }
/* fetch this collection's children */
serr = svn_fs_dir_entries(&children, ctx->info.root.root,
@@ -4267,7 +4435,7 @@ do_walk(walker_ctx_t *ctx,
apr_pstrmemdup(iterpool,
ctx->repos_path->data,
ctx->repos_path->len),
- key, (char *)NULL);
+ key, SVN_VA_NULL);
if (! dav_svn__allow_read(ctx->info.r, ctx->info.repos,
repos_relpath, ctx->info.root.rev,
iterpool))
@@ -4287,7 +4455,10 @@ do_walk(walker_ctx_t *ctx,
{
err = (*params->func)(&ctx->wres, DAV_CALLTYPE_MEMBER);
if (err != NULL)
- return err;
+ {
+ svn_pool_destroy(iterpool);
+ return err;
+ }
}
else
{
@@ -4299,9 +4470,12 @@ do_walk(walker_ctx_t *ctx,
ctx->res.uri = ctx->uri->data;
/* recurse on this collection */
- err = do_walk(ctx, depth - 1, iterpool);
+ err = do_walk(ctx, depth - 1, FALSE, iterpool);
if (err != NULL)
- return err;
+ {
+ svn_pool_destroy(iterpool);
+ return err;
+ }
/* restore the data */
ctx->res.collection = FALSE;
@@ -4381,7 +4555,7 @@ walk(const dav_walk_params *params, int depth, dav_response **response)
/* ### is the root already/always open? need to verify */
/* always return the error, and any/all multistatus responses */
- err = do_walk(&ctx, depth, params->pool);
+ err = do_walk(&ctx, depth, TRUE, params->pool);
*response = ctx.wres.response;
return err;
@@ -4428,7 +4602,7 @@ dav_svn__create_working_resource(dav_resource *base,
if (base->info->repos->root_path[1])
res->uri = apr_pstrcat(base->pool, base->info->repos->root_path,
- path, (char *)NULL);
+ path, SVN_VA_NULL);
else
res->uri = path;
res->hooks = &dav_svn__hooks_repository;
@@ -4481,7 +4655,7 @@ dav_svn__working_to_regular_resource(dav_resource *resource)
/* if rev was specific, create baseline-collection URL */
path = dav_svn__build_uri(repos, DAV_SVN__BUILD_URI_BC,
priv->root.rev, priv->repos_path,
- 0, resource->pool);
+ FALSE /* add_href */, resource->pool);
}
path = svn_path_uri_encode(path, resource->pool);
priv->uri_path = svn_stringbuf_create(path, resource->pool);
@@ -4526,7 +4700,7 @@ dav_svn__create_version_resource(dav_resource **version_res,
static dav_error *
handle_post_request(request_rec *r,
dav_resource *resource,
- ap_filter_t *output)
+ dav_svn__output *output)
{
svn_skel_t *request_skel, *post_skel;
int status;
@@ -4609,7 +4783,9 @@ int dav_svn__method_post(request_rec *r)
content_type = apr_table_get(r->headers_in, "content-type");
if (content_type && (strcmp(content_type, SVN_SKEL_MIME_TYPE) == 0))
{
- derr = handle_post_request(r, resource, r->output_filters);
+ dav_svn__output *output = dav_svn__output_create(resource->info->r,
+ resource->pool);
+ derr = handle_post_request(r, resource, output);
}
else
{