You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2014/01/09 10:31:15 UTC
svn commit: r1556765 [6/12] - in /subversion/branches/fsfs-ucsnorm: ./
contrib/server-side/fsfsfixer/fixer/ subversion/bindings/javahl/native/
subversion/bindings/javahl/native/jniwrapper/
subversion/bindings/javahl/src/org/apache/subversion/javahl/ su...
Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/commit.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/commit.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/commit.c Thu Jan 9 09:31:10 2014
@@ -83,7 +83,7 @@ typedef struct proppatch_context_t {
const char *relpath;
const char *path;
- commit_context_t *commit;
+ commit_context_t *commit_ctx;
/* Changed and removed properties. */
apr_hash_t *changed_props;
@@ -99,14 +99,11 @@ typedef struct proppatch_context_t {
} proppatch_context_t;
typedef struct delete_context_t {
- const char *path;
+ const char *relpath;
svn_revnum_t revision;
- const char *lock_token;
- apr_hash_t *lock_token_hash;
- svn_boolean_t keep_locks;
-
+ commit_context_t *commit_ctx;
} delete_context_t;
/* Represents a directory. */
@@ -115,7 +112,7 @@ typedef struct dir_context_t {
apr_pool_t *pool;
/* The root commit we're in progress for. */
- commit_context_t *commit;
+ commit_context_t *commit_ctx;
/* URL to operate against (used for CHECKOUT and PROPPATCH before
HTTP v2, for PROPPATCH in HTTP v2). */
@@ -149,7 +146,6 @@ typedef struct dir_context_t {
/* The checked-out working resource for this directory. May be NULL; if so
call checkout_dir() first. */
const char *working_url;
-
} dir_context_t;
/* Represents a file to be committed. */
@@ -158,7 +154,7 @@ typedef struct file_context_t {
apr_pool_t *pool;
/* The root commit we're in progress for. */
- commit_context_t *commit;
+ commit_context_t *commit_ctx;
/* Is this file being added? (Otherwise, just opened.) */
svn_boolean_t added;
@@ -202,33 +198,6 @@ typedef struct file_context_t {
/* Setup routines and handlers for various requests we'll invoke. */
-static svn_error_t *
-return_response_err(svn_ra_serf__handler_t *handler)
-{
- svn_error_t *err;
-
- /* We should have captured SLINE and LOCATION in the HANDLER. */
- SVN_ERR_ASSERT(handler->handler_pool != NULL);
-
- /* Ye Olde Fallback Error */
- err = svn_error_compose_create(
- handler->server_error != NULL
- ? handler->server_error->error
- : SVN_NO_ERROR,
- svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
- _("%s of '%s': %d %s"),
- handler->method, handler->path,
- handler->sline.code, handler->sline.reason));
-
- /* Try to return one of the standard errors for 301, 404, etc.,
- then look for an error embedded in the response. */
- return svn_error_compose_create(svn_ra_serf__error_on_status(
- handler->sline,
- handler->path,
- handler->location),
- err);
-}
-
/* Implements svn_ra_serf__request_body_delegate_t */
static svn_error_t *
create_checkout_body(serf_bucket_t **bkt,
@@ -291,32 +260,32 @@ checkout_node(const char **working_url,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- svn_ra_serf__handler_t handler = { 0 };
+ svn_ra_serf__handler_t *handler;
apr_status_t status;
apr_uri_t uri;
/* HANDLER_POOL is the scratch pool since we don't need to remember
anything from the handler. We just want the working resource. */
- handler.handler_pool = scratch_pool;
- handler.session = commit_ctx->session;
- handler.conn = commit_ctx->conn;
-
- handler.body_delegate = create_checkout_body;
- handler.body_delegate_baton = (/* const */ void *)commit_ctx->activity_url;
- handler.body_type = "text/xml";
+ handler = svn_ra_serf__create_handler(scratch_pool);
+ handler->session = commit_ctx->session;
+ handler->conn = commit_ctx->conn;
+
+ handler->body_delegate = create_checkout_body;
+ handler->body_delegate_baton = (/* const */ void *)commit_ctx->activity_url;
+ handler->body_type = "text/xml";
- handler.response_handler = svn_ra_serf__expect_empty_body;
- handler.response_baton = &handler;
+ handler->response_handler = svn_ra_serf__expect_empty_body;
+ handler->response_baton = &handler;
- handler.method = "CHECKOUT";
- handler.path = node_url;
+ handler->method = "CHECKOUT";
+ handler->path = node_url;
- SVN_ERR(svn_ra_serf__context_run_one(&handler, scratch_pool));
+ SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
- if (handler.sline.code != 201)
- return svn_error_trace(return_response_err(&handler));
+ if (handler->sline.code != 201)
+ return svn_error_trace(svn_ra_serf__unexpected_status(handler));
- if (handler.location == NULL)
+ if (handler->location == NULL)
return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
_("No Location header received"));
@@ -325,7 +294,7 @@ checkout_node(const char **working_url,
'https:' transaction ... we'll work around that by stripping the
scheme, host, and port here and re-adding the correct ones
later. */
- status = apr_uri_parse(scratch_pool, handler.location, &uri);
+ status = apr_uri_parse(scratch_pool, handler->location, &uri);
if (status)
return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
_("Error parsing Location header value"));
@@ -371,11 +340,11 @@ retry_checkout_node(const char **working
error and retry a few times, asking for the latest baseline
again. */
if (err && (err->apr_err != SVN_ERR_APMOD_BAD_BASELINE))
- return err;
+ return svn_error_trace(err);
}
while (err && retry_count--);
- return err;
+ return svn_error_trace(err);
}
@@ -383,7 +352,6 @@ static svn_error_t *
checkout_dir(dir_context_t *dir,
apr_pool_t *scratch_pool)
{
- svn_error_t *err;
dir_context_t *c_dir = dir;
const char *checkout_url;
const char **working;
@@ -420,10 +388,10 @@ checkout_dir(dir_context_t *dir,
* once to checkout the directory itself if we need to do so.
* Note: CHECKOUT_URL should live longer than HANDLER.
*/
- if (!dir->parent_dir && !dir->commit->baseline_url)
+ if (!dir->parent_dir && !dir->commit_ctx->baseline_url)
{
- checkout_url = dir->commit->vcc_url;
- working = &dir->commit->baseline_url;
+ checkout_url = dir->commit_ctx->vcc_url;
+ working = &dir->commit_ctx->baseline_url;
}
else
{
@@ -432,18 +400,9 @@ checkout_dir(dir_context_t *dir,
}
/* Checkout our directory into the activity URL now. */
- err = retry_checkout_node(working, dir->commit, checkout_url,
- dir->pool, scratch_pool);
- if (err)
- {
- if (err->apr_err == SVN_ERR_FS_CONFLICT)
- SVN_ERR_W(err, apr_psprintf(scratch_pool,
- _("Directory '%s' is out of date; try updating"),
- svn_dirent_local_style(dir->relpath, scratch_pool)));
- return err;
- }
-
- return SVN_NO_ERROR;
+ return svn_error_trace(retry_checkout_node(working, dir->commit_ctx,
+ checkout_url,
+ dir->pool, scratch_pool));
}
@@ -542,7 +501,6 @@ static svn_error_t *
checkout_file(file_context_t *file,
apr_pool_t *scratch_pool)
{
- svn_error_t *err;
dir_context_t *parent_dir = file->parent_dir;
const char *checkout_url;
@@ -566,23 +524,14 @@ checkout_file(file_context_t *file,
}
SVN_ERR(get_version_url(&checkout_url,
- file->commit->session,
+ file->commit_ctx->session,
file->relpath, file->base_revision,
NULL, scratch_pool, scratch_pool));
/* Checkout our file into the activity URL now. */
- err = retry_checkout_node(&file->working_url, file->commit, checkout_url,
- file->pool, scratch_pool);
- if (err)
- {
- if (err->apr_err == SVN_ERR_FS_CONFLICT)
- SVN_ERR_W(err, apr_psprintf(scratch_pool,
- _("File '%s' is out of date; try updating"),
- svn_dirent_local_style(file->relpath, scratch_pool)));
- return err;
- }
-
- return SVN_NO_ERROR;
+ return svn_error_trace(retry_checkout_node(&file->working_url,
+ file->commit_ctx, checkout_url,
+ file->pool, scratch_pool));
}
/* Helper function for proppatch_walker() below. */
@@ -731,6 +680,8 @@ proppatch_walker(void *baton,
prop_name = apr_pstrcat(wb->body_pool, "S:", name, SVN_VA_NULL);
else if (strcmp(ns, SVN_DAV_PROP_NS_CUSTOM) == 0)
prop_name = apr_pstrcat(wb->body_pool, "C:", name, SVN_VA_NULL);
+ else
+ SVN_ERR_MALFUNCTION();
if (cdata_bkt)
svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, prop_name,
@@ -806,7 +757,7 @@ maybe_set_lock_token_header(serf_bucket_
{
const char *token;
- if (! (relpath && commit_ctx->lock_tokens))
+ if (! (*relpath && commit_ctx->lock_tokens))
return SVN_NO_ERROR;
if (! svn_hash_gets(commit_ctx->deleted_entries, relpath))
@@ -848,20 +799,14 @@ setup_proppatch_headers(serf_bucket_t *h
proppatch->base_revision));
}
- SVN_ERR(maybe_set_lock_token_header(headers, proppatch->commit,
- proppatch->relpath, pool));
+ if (proppatch->relpath && proppatch->commit_ctx)
+ SVN_ERR(maybe_set_lock_token_header(headers, proppatch->commit_ctx,
+ proppatch->relpath, pool));
return SVN_NO_ERROR;
}
-struct proppatch_body_baton_t {
- proppatch_context_t *proppatch;
-
- /* Content in the body should be allocated here, to live long enough. */
- apr_pool_t *body_pool;
-};
-
/* Implements svn_ra_serf__request_body_delegate_t */
static svn_error_t *
create_proppatch_body(serf_bucket_t **bkt,
@@ -869,8 +814,7 @@ create_proppatch_body(serf_bucket_t **bk
serf_bucket_alloc_t *alloc,
apr_pool_t *scratch_pool)
{
- struct proppatch_body_baton_t *pbb = baton;
- proppatch_context_t *ctx = pbb->proppatch;
+ proppatch_context_t *ctx = baton;
serf_bucket_t *body_bkt;
walker_baton_t wb = { 0 };
@@ -885,7 +829,7 @@ create_proppatch_body(serf_bucket_t **bk
SVN_VA_NULL);
wb.body_bkt = body_bkt;
- wb.body_pool = pbb->body_pool;
+ wb.body_pool = scratch_pool;
wb.previous_changed_props = ctx->previous_changed_props;
wb.previous_removed_props = ctx->previous_removed_props;
wb.path = ctx->path;
@@ -945,45 +889,49 @@ create_proppatch_body(serf_bucket_t **bk
}
static svn_error_t*
-proppatch_resource(proppatch_context_t *proppatch,
- commit_context_t *commit,
+proppatch_resource(svn_ra_serf__session_t *session,
+ svn_ra_serf__connection_t *conn,
+ proppatch_context_t *proppatch,
apr_pool_t *pool)
{
svn_ra_serf__handler_t *handler;
- struct proppatch_body_baton_t pbb;
+ svn_error_t *err;
+
+ handler = svn_ra_serf__create_handler(pool);
- handler = apr_pcalloc(pool, sizeof(*handler));
- handler->handler_pool = pool;
handler->method = "PROPPATCH";
handler->path = proppatch->path;
- handler->conn = commit->conn;
- handler->session = commit->session;
+ handler->conn = conn;
+ handler->session = session;
handler->header_delegate = setup_proppatch_headers;
handler->header_delegate_baton = proppatch;
- pbb.proppatch = proppatch;
- pbb.body_pool = pool;
handler->body_delegate = create_proppatch_body;
- handler->body_delegate_baton = &pbb;
+ handler->body_delegate_baton = proppatch;
handler->response_handler = svn_ra_serf__handle_multistatus_only;
handler->response_baton = handler;
- SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
+ err = svn_ra_serf__context_run_one(handler, pool);
- if (handler->sline.code != 207
- || (handler->server_error != NULL
- && handler->server_error->error != NULL))
- {
- return svn_error_create(
- SVN_ERR_RA_DAV_PROPPATCH_FAILED,
- return_response_err(handler),
- _("At least one property change failed; repository"
- " is unchanged"));
+ if (!err && handler->sline.code != 207)
+ err = svn_error_trace(svn_ra_serf__unexpected_status(handler));
+
+ /* Use specific error code for property handling errors.
+ Use loop to provide the right result with tracing */
+ if (err && err->apr_err == SVN_ERR_RA_DAV_REQUEST_FAILED)
+ {
+ svn_error_t *e = err;
+
+ while (e && e->apr_err == SVN_ERR_RA_DAV_REQUEST_FAILED)
+ {
+ e->apr_err = SVN_ERR_RA_DAV_PROPPATCH_FAILED;
+ e = e->child;
+ }
}
- return SVN_NO_ERROR;
+ return svn_error_trace(err);
}
/* Implements svn_ra_serf__request_body_delegate_t */
@@ -1052,7 +1000,7 @@ setup_put_headers(serf_bucket_t *headers
ctx->result_checksum);
}
- SVN_ERR(maybe_set_lock_token_header(headers, ctx->commit,
+ SVN_ERR(maybe_set_lock_token_header(headers, ctx->commit_ctx,
ctx->relpath, pool));
return APR_SUCCESS;
@@ -1068,19 +1016,105 @@ setup_copy_file_headers(serf_bucket_t *h
const char *absolute_uri;
/* The Dest URI must be absolute. Bummer. */
- uri = file->commit->session->session_url;
+ uri = file->commit_ctx->session->session_url;
uri.path = (char*)file->url;
absolute_uri = apr_uri_unparse(pool, &uri, 0);
serf_bucket_headers_set(headers, "Destination", absolute_uri);
- serf_bucket_headers_setn(headers, "Depth", "0");
- serf_bucket_headers_setn(headers, "Overwrite", "T");
+ serf_bucket_headers_setn(headers, "Overwrite", "F");
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+setup_if_header_recursive(svn_boolean_t *added,
+ serf_bucket_t *headers,
+ commit_context_t *commit_ctx,
+ const char *rq_relpath,
+ apr_pool_t *pool)
+{
+ svn_stringbuf_t *sb = NULL;
+ apr_hash_index_t *hi;
+ apr_pool_t *iterpool = NULL;
+
+ if (!commit_ctx->lock_tokens)
+ return SVN_NO_ERROR;
+
+ /* We try to create a directory, so within the Subversion world that
+ would imply that there is nothing here, but mod_dav_svn still sees
+ locks on the old nodes here as in DAV it is perfectly legal to lock
+ something that is not there...
+
+ Let's make mod_dav, mod_dav_svn and the DAV RFC happy by providing
+ the locks we know of with the request */
+
+ for (hi = apr_hash_first(pool, commit_ctx->lock_tokens);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ const char *relpath = svn__apr_hash_index_key(hi);
+ apr_uri_t uri;
+
+ if (!svn_relpath_skip_ancestor(rq_relpath, relpath))
+ continue;
+ else if (svn_hash_gets(commit_ctx->deleted_entries, relpath))
+ {
+ /* When a path is already explicit deleted then its lock
+ will be removed by mod_dav. But mod_dav doesn't remove
+ locks on descendants */
+ continue;
+ }
+
+ if (!iterpool)
+ iterpool = svn_pool_create(pool);
+ else
+ svn_pool_clear(iterpool);
+
+ if (sb == NULL)
+ sb = svn_stringbuf_create("", pool);
+ else
+ svn_stringbuf_appendbyte(sb, ' ');
+
+ uri = commit_ctx->session->session_url;
+ uri.path = (char *)svn_path_url_add_component2(uri.path, relpath,
+ iterpool);
+
+ svn_stringbuf_appendbyte(sb, '<');
+ svn_stringbuf_appendcstr(sb, apr_uri_unparse(iterpool, &uri, 0));
+ svn_stringbuf_appendcstr(sb, "> (<");
+ svn_stringbuf_appendcstr(sb, svn__apr_hash_index_val(hi));
+ svn_stringbuf_appendcstr(sb, ">)");
+ }
+
+ if (iterpool)
+ svn_pool_destroy(iterpool);
+
+ if (sb)
+ {
+ serf_bucket_headers_set(headers, "If", sb->data);
+ *added = TRUE;
+ }
+ else
+ *added = FALSE;
return SVN_NO_ERROR;
}
static svn_error_t *
+setup_add_dir_common_headers(serf_bucket_t *headers,
+ void *baton,
+ apr_pool_t *pool)
+{
+ dir_context_t *dir = baton;
+ svn_boolean_t added;
+
+ return svn_error_trace(
+ setup_if_header_recursive(&added, headers, dir->commit_ctx, dir->relpath,
+ pool));
+}
+
+static svn_error_t *
setup_copy_dir_headers(serf_bucket_t *headers,
void *baton,
apr_pool_t *pool)
@@ -1090,9 +1124,9 @@ setup_copy_dir_headers(serf_bucket_t *he
const char *absolute_uri;
/* The Dest URI must be absolute. Bummer. */
- uri = dir->commit->session->session_url;
+ uri = dir->commit_ctx->session->session_url;
- if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit))
+ if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit_ctx))
{
uri.path = (char *)dir->url;
}
@@ -1107,12 +1141,12 @@ setup_copy_dir_headers(serf_bucket_t *he
serf_bucket_headers_set(headers, "Destination", absolute_uri);
serf_bucket_headers_setn(headers, "Depth", "infinity");
- serf_bucket_headers_setn(headers, "Overwrite", "T");
+ serf_bucket_headers_setn(headers, "Overwrite", "F");
/* Implicitly checkout this dir now. */
dir->working_url = apr_pstrdup(dir->pool, uri.path);
- return SVN_NO_ERROR;
+ return svn_error_trace(setup_add_dir_common_headers(headers, baton, pool));
}
static svn_error_t *
@@ -1120,72 +1154,22 @@ setup_delete_headers(serf_bucket_t *head
void *baton,
apr_pool_t *pool)
{
- delete_context_t *ctx = baton;
+ delete_context_t *del = baton;
+ svn_boolean_t added;
serf_bucket_headers_set(headers, SVN_DAV_VERSION_NAME_HEADER,
- apr_ltoa(pool, ctx->revision));
-
- if (ctx->lock_token_hash)
- {
- ctx->lock_token = svn_hash_gets(ctx->lock_token_hash, ctx->path);
-
- if (ctx->lock_token)
- {
- const char *token_header;
-
- token_header = apr_pstrcat(pool, "<", ctx->path, "> (<",
- ctx->lock_token, ">)", SVN_VA_NULL);
-
- serf_bucket_headers_set(headers, "If", token_header);
-
- if (ctx->keep_locks)
- serf_bucket_headers_setn(headers, SVN_DAV_OPTIONS_HEADER,
- SVN_DAV_OPTION_KEEP_LOCKS);
- }
- }
-
- return SVN_NO_ERROR;
-}
+ apr_ltoa(pool, del->revision));
-/* Implements svn_ra_serf__request_body_delegate_t */
-static svn_error_t *
-create_delete_body(serf_bucket_t **body_bkt,
- void *baton,
- serf_bucket_alloc_t *alloc,
- apr_pool_t *pool)
-{
- delete_context_t *ctx = baton;
- serf_bucket_t *body;
-
- body = serf_bucket_aggregate_create(alloc);
-
- svn_ra_serf__add_xml_header_buckets(body, alloc);
-
- svn_ra_serf__merge_lock_token_list(ctx->lock_token_hash, ctx->path,
- body, alloc, pool);
-
- *body_bkt = body;
- return SVN_NO_ERROR;
-}
-
-/* Helper function to write the svndiff stream to temporary file. */
-static svn_error_t *
-svndiff_stream_write(void *file_baton,
- const char *data,
- apr_size_t *len)
-{
- file_context_t *ctx = file_baton;
- apr_status_t status;
+ SVN_ERR(setup_if_header_recursive(&added, headers, del->commit_ctx,
+ del->relpath, pool));
- status = apr_file_write_full(ctx->svndiff, data, *len, NULL);
- if (status)
- return svn_error_wrap_apr(status, _("Failed writing updated file"));
+ if (added && del->commit_ctx->keep_locks)
+ serf_bucket_headers_setn(headers, SVN_DAV_OPTIONS_HEADER,
+ SVN_DAV_OPTION_KEEP_LOCKS);
return SVN_NO_ERROR;
}
-
-
/* POST against 'me' resource handlers. */
/* Implements svn_ra_serf__request_body_delegate_t */
@@ -1314,66 +1298,49 @@ open_root(void *edit_baton,
apr_pool_t *dir_pool,
void **root_baton)
{
- commit_context_t *ctx = edit_baton;
+ commit_context_t *commit_ctx = edit_baton;
svn_ra_serf__handler_t *handler;
proppatch_context_t *proppatch_ctx;
dir_context_t *dir;
apr_hash_index_t *hi;
const char *proppatch_target = NULL;
+ apr_pool_t *scratch_pool = svn_pool_create(dir_pool);
- if (SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(ctx->session))
+ if (SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(commit_ctx->session))
{
post_response_ctx_t *prc;
const char *rel_path;
svn_boolean_t post_with_revprops
- = (NULL != svn_hash_gets(ctx->session->supported_posts,
+ = (NULL != svn_hash_gets(commit_ctx->session->supported_posts,
"create-txn-with-props"));
/* Create our activity URL now on the server. */
- handler = apr_pcalloc(ctx->pool, sizeof(*handler));
- handler->handler_pool = ctx->pool;
+ handler = svn_ra_serf__create_handler(scratch_pool);
+
handler->method = "POST";
handler->body_type = SVN_SKEL_MIME_TYPE;
handler->body_delegate = create_txn_post_body;
handler->body_delegate_baton =
- post_with_revprops ? ctx->revprop_table : NULL;
+ post_with_revprops ? commit_ctx->revprop_table : NULL;
handler->header_delegate = setup_post_headers;
handler->header_delegate_baton = NULL;
- handler->path = ctx->session->me_resource;
- handler->conn = ctx->session->conns[0];
- handler->session = ctx->session;
+ handler->path = commit_ctx->session->me_resource;
+ handler->conn = commit_ctx->session->conns[0];
+ handler->session = commit_ctx->session;
- prc = apr_pcalloc(ctx->pool, sizeof(*prc));
+ prc = apr_pcalloc(scratch_pool, sizeof(*prc));
prc->handler = handler;
- prc->commit_ctx = ctx;
+ prc->commit_ctx = commit_ctx;
handler->response_handler = post_response_handler;
handler->response_baton = prc;
- SVN_ERR(svn_ra_serf__context_run_one(handler, ctx->pool));
+ SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
if (handler->sline.code != 201)
- {
- apr_status_t status = SVN_ERR_RA_DAV_REQUEST_FAILED;
-
- switch (handler->sline.code)
- {
- case 403:
- status = SVN_ERR_RA_DAV_FORBIDDEN;
- break;
- case 404:
- status = SVN_ERR_FS_NOT_FOUND;
- break;
- }
+ return svn_error_trace(svn_ra_serf__unexpected_status(handler));
- return svn_error_createf(status, NULL,
- _("%s of '%s': %d %s (%s://%s)"),
- handler->method, handler->path,
- handler->sline.code, handler->sline.reason,
- ctx->session->session_url.scheme,
- ctx->session->session_url.hostinfo);
- }
- if (! (ctx->txn_root_url && ctx->txn_url))
+ if (! (commit_ctx->txn_root_url && commit_ctx->txn_url))
{
return svn_error_createf(
SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
@@ -1381,42 +1348,45 @@ open_root(void *edit_baton,
}
/* Fixup the txn_root_url to point to the anchor of the commit. */
- SVN_ERR(svn_ra_serf__get_relative_path(&rel_path,
- ctx->session->session_url.path,
- ctx->session, NULL, dir_pool));
- ctx->txn_root_url = svn_path_url_add_component2(ctx->txn_root_url,
- rel_path, ctx->pool);
+ SVN_ERR(svn_ra_serf__get_relative_path(
+ &rel_path,
+ commit_ctx->session->session_url.path,
+ commit_ctx->session, NULL,
+ scratch_pool));
+ commit_ctx->txn_root_url = svn_path_url_add_component2(
+ commit_ctx->txn_root_url,
+ rel_path, commit_ctx->pool);
/* Build our directory baton. */
dir = apr_pcalloc(dir_pool, sizeof(*dir));
dir->pool = dir_pool;
- dir->commit = ctx;
+ dir->commit_ctx = commit_ctx;
dir->base_revision = base_revision;
dir->relpath = "";
dir->name = "";
dir->changed_props = apr_hash_make(dir->pool);
dir->removed_props = apr_hash_make(dir->pool);
- dir->url = apr_pstrdup(dir->pool, ctx->txn_root_url);
+ dir->url = apr_pstrdup(dir->pool, commit_ctx->txn_root_url);
/* If we included our revprops in the POST, we need not
PROPPATCH them. */
- proppatch_target = post_with_revprops ? NULL : ctx->txn_url;
+ proppatch_target = post_with_revprops ? NULL : commit_ctx->txn_url;
}
else
{
- const char *activity_str = ctx->session->activity_collection_url;
+ const char *activity_str = commit_ctx->session->activity_collection_url;
if (!activity_str)
- SVN_ERR(svn_ra_serf__v1_get_activity_collection(&activity_str,
- ctx->session->conns[0],
- ctx->pool,
- ctx->pool));
+ SVN_ERR(svn_ra_serf__v1_get_activity_collection(
+ &activity_str,
+ commit_ctx->session->conns[0],
+ commit_ctx->pool, scratch_pool));
/* Cache the result. */
if (activity_str)
{
- ctx->session->activity_collection_url =
- apr_pstrdup(ctx->session->pool, activity_str);
+ commit_ctx->session->activity_collection_url =
+ apr_pstrdup(commit_ctx->session->pool, activity_str);
}
else
{
@@ -1425,70 +1395,53 @@ open_root(void *edit_baton,
"requested activity-collection-set value"));
}
- ctx->activity_url =
- svn_path_url_add_component2(activity_str, svn_uuid_generate(ctx->pool),
- ctx->pool);
+ commit_ctx->activity_url = svn_path_url_add_component2(
+ activity_str,
+ svn_uuid_generate(scratch_pool),
+ commit_ctx->pool);
/* Create our activity URL now on the server. */
- handler = apr_pcalloc(ctx->pool, sizeof(*handler));
- handler->handler_pool = ctx->pool;
+ handler = svn_ra_serf__create_handler(scratch_pool);
+
handler->method = "MKACTIVITY";
- handler->path = ctx->activity_url;
- handler->conn = ctx->session->conns[0];
- handler->session = ctx->session;
+ handler->path = commit_ctx->activity_url;
+ handler->conn = commit_ctx->session->conns[0];
+ handler->session = commit_ctx->session;
handler->response_handler = svn_ra_serf__expect_empty_body;
handler->response_baton = handler;
- SVN_ERR(svn_ra_serf__context_run_one(handler, ctx->pool));
+ SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
if (handler->sline.code != 201)
- {
- apr_status_t status = SVN_ERR_RA_DAV_REQUEST_FAILED;
-
- switch (handler->sline.code)
- {
- case 403:
- status = SVN_ERR_RA_DAV_FORBIDDEN;
- break;
- case 404:
- status = SVN_ERR_FS_NOT_FOUND;
- break;
- }
-
- return svn_error_createf(status, NULL,
- _("%s of '%s': %d %s (%s://%s)"),
- handler->method, handler->path,
- handler->sline.code, handler->sline.reason,
- ctx->session->session_url.scheme,
- ctx->session->session_url.hostinfo);
- }
+ return svn_error_trace(svn_ra_serf__unexpected_status(handler));
/* Now go fetch our VCC and baseline so we can do a CHECKOUT. */
- SVN_ERR(svn_ra_serf__discover_vcc(&(ctx->vcc_url), ctx->session,
- ctx->conn, ctx->pool));
+ SVN_ERR(svn_ra_serf__discover_vcc(&(commit_ctx->vcc_url),
+ commit_ctx->session,
+ commit_ctx->conn, commit_ctx->pool));
/* Build our directory baton. */
dir = apr_pcalloc(dir_pool, sizeof(*dir));
dir->pool = dir_pool;
- dir->commit = ctx;
+ dir->commit_ctx = commit_ctx;
dir->base_revision = base_revision;
dir->relpath = "";
dir->name = "";
dir->changed_props = apr_hash_make(dir->pool);
dir->removed_props = apr_hash_make(dir->pool);
- SVN_ERR(get_version_url(&dir->url, dir->commit->session,
+ SVN_ERR(get_version_url(&dir->url, dir->commit_ctx->session,
dir->relpath,
- dir->base_revision, ctx->checked_in_url,
- dir->pool, dir->pool /* scratch_pool */));
- ctx->checked_in_url = dir->url;
+ dir->base_revision, commit_ctx->checked_in_url,
+ dir->pool, scratch_pool));
+ commit_ctx->checked_in_url = apr_pstrdup(commit_ctx->pool, dir->url);
/* Checkout our root dir */
- SVN_ERR(checkout_dir(dir, dir->pool /* scratch_pool */));
+ SVN_ERR(checkout_dir(dir, scratch_pool));
- proppatch_target = ctx->baseline_url;
+ proppatch_target = commit_ctx->baseline_url;
}
/* Unless this is NULL -- which means we don't need to PROPPATCH the
@@ -1496,15 +1449,16 @@ open_root(void *edit_baton,
transaction with our revprops. */
if (proppatch_target)
{
- proppatch_ctx = apr_pcalloc(ctx->pool, sizeof(*proppatch_ctx));
- proppatch_ctx->pool = dir_pool;
- proppatch_ctx->commit = ctx;
+ proppatch_ctx = apr_pcalloc(scratch_pool, sizeof(*proppatch_ctx));
+ proppatch_ctx->pool = scratch_pool;
+ proppatch_ctx->commit_ctx = NULL; /* No lock info */
proppatch_ctx->path = proppatch_target;
proppatch_ctx->changed_props = apr_hash_make(proppatch_ctx->pool);
proppatch_ctx->removed_props = apr_hash_make(proppatch_ctx->pool);
proppatch_ctx->base_revision = SVN_INVALID_REVNUM;
- for (hi = apr_hash_first(ctx->pool, ctx->revprop_table); hi;
+ for (hi = apr_hash_first(scratch_pool, commit_ctx->revprop_table);
+ hi;
hi = apr_hash_next(hi))
{
const char *name = svn__apr_hash_index_key(hi);
@@ -1523,12 +1477,16 @@ open_root(void *edit_baton,
svn_ra_serf__set_prop(proppatch_ctx->changed_props,
proppatch_ctx->path,
- ns, name, value, proppatch_ctx->pool);
+ ns, name, value, scratch_pool);
}
- SVN_ERR(proppatch_resource(proppatch_ctx, dir->commit, ctx->pool));
+ SVN_ERR(proppatch_resource(commit_ctx->session,
+ commit_ctx->conn,
+ proppatch_ctx, scratch_pool));
}
+ svn_pool_destroy(scratch_pool);
+
*root_baton = dir;
return SVN_NO_ERROR;
@@ -1544,12 +1502,12 @@ delete_entry(const char *path,
delete_context_t *delete_ctx;
svn_ra_serf__handler_t *handler;
const char *delete_target;
- svn_error_t *err;
- if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit))
+ if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit_ctx))
{
- delete_target = svn_path_url_add_component2(dir->commit->txn_root_url,
- path, dir->pool);
+ delete_target = svn_path_url_add_component2(
+ dir->commit_ctx->txn_root_url,
+ path, dir->pool);
}
else
{
@@ -1563,15 +1521,13 @@ delete_entry(const char *path,
/* DELETE our entry */
delete_ctx = apr_pcalloc(pool, sizeof(*delete_ctx));
- delete_ctx->path = apr_pstrdup(pool, path);
+ delete_ctx->relpath = apr_pstrdup(pool, path);
delete_ctx->revision = revision;
- delete_ctx->lock_token_hash = dir->commit->lock_tokens;
- delete_ctx->keep_locks = dir->commit->keep_locks;
+ delete_ctx->commit_ctx = dir->commit_ctx;
- handler = apr_pcalloc(pool, sizeof(*handler));
- handler->handler_pool = pool;
- handler->session = dir->commit->session;
- handler->conn = dir->commit->conn;
+ handler = svn_ra_serf__create_handler(pool);
+ handler->session = dir->commit_ctx->session;
+ handler->conn = dir->commit_ctx->conn;
handler->response_handler = svn_ra_serf__expect_empty_body;
handler->response_baton = handler;
@@ -1582,39 +1538,14 @@ delete_entry(const char *path,
handler->method = "DELETE";
handler->path = delete_target;
- err = svn_ra_serf__context_run_one(handler, pool);
-
- if (err &&
- (err->apr_err == SVN_ERR_FS_BAD_LOCK_TOKEN ||
- err->apr_err == SVN_ERR_FS_NO_LOCK_TOKEN ||
- err->apr_err == SVN_ERR_FS_LOCK_OWNER_MISMATCH ||
- err->apr_err == SVN_ERR_FS_PATH_ALREADY_LOCKED))
- {
- svn_error_clear(err);
-
- /* An error has been registered on the connection. Reset the thing
- so that we can use it again. */
- serf_connection_reset(handler->conn->conn);
-
- handler->body_delegate = create_delete_body;
- handler->body_delegate_baton = delete_ctx;
- handler->body_type = "text/xml";
-
- SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
- }
- else if (err)
- {
- return err;
- }
+ SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
/* 204 No Content: item successfully deleted */
if (handler->sline.code != 204)
- {
- return svn_error_trace(return_response_err(handler));
- }
+ return svn_error_trace(svn_ra_serf__unexpected_status(handler));
- svn_hash_sets(dir->commit->deleted_entries,
- apr_pstrdup(dir->commit->pool, path), (void *)1);
+ svn_hash_sets(dir->commit_ctx->deleted_entries,
+ apr_pstrdup(dir->commit_ctx->pool, path), (void *)1);
return SVN_NO_ERROR;
}
@@ -1637,19 +1568,19 @@ add_directory(const char *path,
dir->pool = dir_pool;
dir->parent_dir = parent;
- dir->commit = parent->commit;
+ dir->commit_ctx = parent->commit_ctx;
dir->added = TRUE;
dir->base_revision = SVN_INVALID_REVNUM;
dir->copy_revision = copyfrom_revision;
- dir->copy_path = copyfrom_path;
+ dir->copy_path = apr_pstrdup(dir->pool, copyfrom_path);
dir->relpath = apr_pstrdup(dir->pool, path);
dir->name = svn_relpath_basename(dir->relpath, NULL);
dir->changed_props = apr_hash_make(dir->pool);
dir->removed_props = apr_hash_make(dir->pool);
- if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit))
+ if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit_ctx))
{
- dir->url = svn_path_url_add_component2(parent->commit->txn_root_url,
+ dir->url = svn_path_url_add_component2(parent->commit_ctx->txn_root_url,
path, dir->pool);
mkcol_target = dir->url;
}
@@ -1658,17 +1589,16 @@ add_directory(const char *path,
/* Ensure our parent is checked out. */
SVN_ERR(checkout_dir(parent, dir->pool /* scratch_pool */));
- dir->url = svn_path_url_add_component2(parent->commit->checked_in_url,
+ dir->url = svn_path_url_add_component2(parent->commit_ctx->checked_in_url,
dir->name, dir->pool);
mkcol_target = svn_path_url_add_component2(
parent->working_url,
dir->name, dir->pool);
}
- handler = apr_pcalloc(dir->pool, sizeof(*handler));
- handler->handler_pool = dir->pool;
- handler->conn = dir->commit->conn;
- handler->session = dir->commit->session;
+ handler = svn_ra_serf__create_handler(dir->pool);
+ handler->conn = dir->commit_ctx->conn;
+ handler->session = dir->commit_ctx->session;
handler->response_handler = svn_ra_serf__expect_empty_body;
handler->response_baton = handler;
@@ -1676,6 +1606,9 @@ add_directory(const char *path,
{
handler->method = "MKCOL";
handler->path = mkcol_target;
+
+ handler->header_delegate = setup_add_dir_common_headers;
+ handler->header_delegate_baton = dir;
}
else
{
@@ -1692,7 +1625,7 @@ add_directory(const char *path,
/* ### conn==NULL for session->conns[0]. same as commit->conn. */
SVN_ERR(svn_ra_serf__get_stable_url(&req_url, NULL /* latest_revnum */,
- dir->commit->session,
+ dir->commit_ctx->session,
NULL /* conn */,
uri.path, dir->copy_revision,
dir_pool, dir_pool));
@@ -1706,23 +1639,8 @@ add_directory(const char *path,
SVN_ERR(svn_ra_serf__context_run_one(handler, dir->pool));
- switch (handler->sline.code)
- {
- case 201: /* Created: item was successfully copied */
- case 204: /* No Content: item successfully replaced an existing target */
- break;
-
- case 403:
- return svn_error_createf(SVN_ERR_RA_DAV_FORBIDDEN, NULL,
- _("Access to '%s' forbidden"),
- handler->path);
- default:
- return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
- _("Adding directory failed: %s on %s "
- "(%d %s)"),
- handler->method, handler->path,
- handler->sline.code, handler->sline.reason);
- }
+ if (handler->sline.code != 201)
+ return svn_error_trace(svn_ra_serf__unexpected_status(handler));
*child_baton = dir;
@@ -1744,7 +1662,7 @@ open_directory(const char *path,
dir->pool = dir_pool;
dir->parent_dir = parent;
- dir->commit = parent->commit;
+ dir->commit_ctx = parent->commit_ctx;
dir->added = FALSE;
dir->base_revision = base_revision;
@@ -1753,17 +1671,17 @@ open_directory(const char *path,
dir->changed_props = apr_hash_make(dir->pool);
dir->removed_props = apr_hash_make(dir->pool);
- if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit))
+ if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit_ctx))
{
- dir->url = svn_path_url_add_component2(parent->commit->txn_root_url,
+ dir->url = svn_path_url_add_component2(parent->commit_ctx->txn_root_url,
path, dir->pool);
}
else
{
SVN_ERR(get_version_url(&dir->url,
- dir->commit->session,
+ dir->commit_ctx->session,
dir->relpath, dir->base_revision,
- dir->commit->checked_in_url,
+ dir->commit_ctx->checked_in_url,
dir->pool, dir->pool /* scratch_pool */));
}
*child_baton = dir;
@@ -1782,7 +1700,7 @@ change_dir_prop(void *dir_baton,
const char *proppatch_target;
- if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit))
+ if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit_ctx))
{
proppatch_target = dir->url;
}
@@ -1839,13 +1757,13 @@ close_directory(void *dir_baton,
proppatch_ctx = apr_pcalloc(pool, sizeof(*proppatch_ctx));
proppatch_ctx->pool = pool;
- proppatch_ctx->commit = dir->commit;
+ proppatch_ctx->commit_ctx = dir->commit_ctx;
proppatch_ctx->relpath = dir->relpath;
proppatch_ctx->changed_props = dir->changed_props;
proppatch_ctx->removed_props = dir->removed_props;
proppatch_ctx->base_revision = dir->base_revision;
- if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit))
+ if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit_ctx))
{
proppatch_ctx->path = dir->url;
}
@@ -1854,7 +1772,9 @@ close_directory(void *dir_baton,
proppatch_ctx->path = dir->working_url;
}
- SVN_ERR(proppatch_resource(proppatch_ctx, dir->commit, dir->pool));
+ SVN_ERR(proppatch_resource(dir->commit_ctx->session,
+ dir->commit_ctx->conn,
+ proppatch_ctx, dir->pool));
}
return SVN_NO_ERROR;
@@ -1871,6 +1791,7 @@ add_file(const char *path,
dir_context_t *dir = parent_baton;
file_context_t *new_file;
const char *deleted_parent = path;
+ apr_pool_t *scratch_pool = svn_pool_create(file_pool);
new_file = apr_pcalloc(file_pool, sizeof(*new_file));
new_file->pool = file_pool;
@@ -1878,12 +1799,12 @@ add_file(const char *path,
dir->ref_count++;
new_file->parent_dir = dir;
- new_file->commit = dir->commit;
+ new_file->commit_ctx = dir->commit_ctx;
new_file->relpath = apr_pstrdup(new_file->pool, path);
new_file->name = svn_relpath_basename(new_file->relpath, NULL);
new_file->added = TRUE;
new_file->base_revision = SVN_INVALID_REVNUM;
- new_file->copy_path = copy_path;
+ new_file->copy_path = apr_pstrdup(new_file->pool, copy_path);
new_file->copy_revision = copy_revision;
new_file->changed_props = apr_hash_make(new_file->pool);
new_file->removed_props = apr_hash_make(new_file->pool);
@@ -1891,9 +1812,9 @@ add_file(const char *path,
/* Ensure that the file doesn't exist by doing a HEAD on the
resource. If we're using HTTP v2, we'll just look into the
transaction root tree for this thing. */
- if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit))
+ if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit_ctx))
{
- new_file->url = svn_path_url_add_component2(dir->commit->txn_root_url,
+ new_file->url = svn_path_url_add_component2(dir->commit_ctx->txn_root_url,
path, new_file->pool);
}
else
@@ -1908,42 +1829,82 @@ add_file(const char *path,
while (deleted_parent && deleted_parent[0] != '\0')
{
- if (svn_hash_gets(dir->commit->deleted_entries, deleted_parent))
+ if (svn_hash_gets(dir->commit_ctx->deleted_entries, deleted_parent))
{
break;
}
deleted_parent = svn_relpath_dirname(deleted_parent, file_pool);
}
- if (! ((dir->added && !dir->copy_path) ||
- (deleted_parent && deleted_parent[0] != '\0')))
+ if (copy_path)
+ {
+ svn_ra_serf__handler_t *handler;
+ apr_uri_t uri;
+ const char *req_url;
+
+ apr_status_t status;
+
+ /* Create the copy directly as cheap 'does exist/out of date'
+ check. We update the copy (if needed) from close_file() */
+
+ status = apr_uri_parse(scratch_pool, copy_path, &uri);
+ if (status)
+ return svn_ra_serf__wrap_err(status, NULL);
+
+ /* ### conn==NULL for session->conns[0]. same as commit_ctx->conn. */
+ SVN_ERR(svn_ra_serf__get_stable_url(&req_url, NULL /* latest_revnum */,
+ dir->commit_ctx->session,
+ NULL /* conn */,
+ uri.path, copy_revision,
+ scratch_pool, scratch_pool));
+
+ handler = svn_ra_serf__create_handler(scratch_pool);
+ handler->method = "COPY";
+ handler->path = req_url;
+ handler->conn = dir->commit_ctx->conn;
+ handler->session = dir->commit_ctx->session;
+
+ handler->response_handler = svn_ra_serf__expect_empty_body;
+ handler->response_baton = handler;
+
+ handler->header_delegate = setup_copy_file_headers;
+ handler->header_delegate_baton = new_file;
+
+ SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
+
+ if (handler->sline.code != 201)
+ return svn_error_trace(svn_ra_serf__unexpected_status(handler));
+ }
+ else if (! ((dir->added && !dir->copy_path) ||
+ (deleted_parent && deleted_parent[0] != '\0')))
{
svn_ra_serf__handler_t *handler;
+ svn_error_t *err;
- handler = apr_pcalloc(new_file->pool, sizeof(*handler));
- handler->handler_pool = new_file->pool;
- handler->session = new_file->commit->session;
- handler->conn = new_file->commit->conn;
+ handler = svn_ra_serf__create_handler(scratch_pool);
+ handler->session = new_file->commit_ctx->session;
+ handler->conn = new_file->commit_ctx->conn;
handler->method = "HEAD";
handler->path = svn_path_url_add_component2(
- dir->commit->session->session_url.path,
- path, new_file->pool);
+ dir->commit_ctx->session->session_url.path,
+ path, scratch_pool);
handler->response_handler = svn_ra_serf__expect_empty_body;
handler->response_baton = handler;
- SVN_ERR(svn_ra_serf__context_run_one(handler, new_file->pool));
+ err = svn_ra_serf__context_run_one(handler, scratch_pool);
- if (handler->sline.code != 404)
+ if (err && err->apr_err == SVN_ERR_FS_NOT_FOUND)
{
- SVN_ERR(svn_ra_serf__error_on_status(handler->sline,
- handler->path,
- handler->location));
-
- return svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL,
- _("File '%s' already exists"), path);
+ svn_error_clear(err); /* Great. We can create a new file! */
}
+ else if (err)
+ return svn_error_trace(err);
+ else
+ return svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL,
+ _("File '%s' already exists"), path);
}
+ svn_pool_destroy(scratch_pool);
*file_baton = new_file;
return SVN_NO_ERROR;
@@ -1965,7 +1926,7 @@ open_file(const char *path,
parent->ref_count++;
new_file->parent_dir = parent;
- new_file->commit = parent->commit;
+ new_file->commit_ctx = parent->commit_ctx;
new_file->relpath = apr_pstrdup(new_file->pool, path);
new_file->name = svn_relpath_basename(new_file->relpath, NULL);
new_file->added = FALSE;
@@ -1973,9 +1934,9 @@ open_file(const char *path,
new_file->changed_props = apr_hash_make(new_file->pool);
new_file->removed_props = apr_hash_make(new_file->pool);
- if (USING_HTTPV2_COMMIT_SUPPORT(parent->commit))
+ if (USING_HTTPV2_COMMIT_SUPPORT(parent->commit_ctx))
{
- new_file->url = svn_path_url_add_component2(parent->commit->txn_root_url,
+ new_file->url = svn_path_url_add_component2(parent->commit_ctx->txn_root_url,
path, new_file->pool);
}
else
@@ -1991,6 +1952,23 @@ open_file(const char *path,
return SVN_NO_ERROR;
}
+/* Implements svn_stream_lazyopen_func_t for apply_textdelta */
+static svn_error_t *
+delayed_commit_stream_open(svn_stream_t **stream,
+ void *baton,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ file_context_t *file_ctx = baton;
+
+ SVN_ERR(svn_io_open_unique_file3(&file_ctx->svndiff, NULL, NULL,
+ svn_io_file_del_on_pool_cleanup,
+ file_ctx->pool, scratch_pool));
+
+ *stream = svn_stream_from_aprfile2(file_ctx->svndiff, TRUE, result_pool);
+ return SVN_NO_ERROR;
+}
+
static svn_error_t *
apply_textdelta(void *file_baton,
const char *base_checksum,
@@ -2013,12 +1991,8 @@ apply_textdelta(void *file_baton,
* avoid too many simultaneously open files.
*/
- SVN_ERR(svn_io_open_unique_file3(&ctx->svndiff, NULL, NULL,
- svn_io_file_del_on_pool_cleanup,
- ctx->pool, pool));
-
- ctx->stream = svn_stream_create(ctx, pool);
- svn_stream_set_write(ctx->stream, svndiff_stream_write);
+ ctx->stream = svn_stream_lazyopen_create(delayed_commit_stream_open,
+ ctx, FALSE, ctx->pool);
svn_txdelta_to_svndiff3(handler, handler_baton, ctx->stream, 0,
SVN_DELTA_COMPRESSION_LEVEL_DEFAULT, pool);
@@ -2074,69 +2048,27 @@ close_file(void *file_baton,
{
file_context_t *ctx = file_baton;
svn_boolean_t put_empty_file = FALSE;
- apr_status_t status;
ctx->result_checksum = text_checksum;
- if (ctx->copy_path)
- {
- svn_ra_serf__handler_t *handler;
- apr_uri_t uri;
- const char *req_url;
-
- status = apr_uri_parse(scratch_pool, ctx->copy_path, &uri);
- if (status)
- {
- return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
- _("Unable to parse URL '%s'"),
- ctx->copy_path);
- }
-
- /* ### conn==NULL for session->conns[0]. same as commit->conn. */
- SVN_ERR(svn_ra_serf__get_stable_url(&req_url, NULL /* latest_revnum */,
- ctx->commit->session,
- NULL /* conn */,
- uri.path, ctx->copy_revision,
- scratch_pool, scratch_pool));
-
- handler = apr_pcalloc(scratch_pool, sizeof(*handler));
- handler->handler_pool = scratch_pool;
- handler->method = "COPY";
- handler->path = req_url;
- handler->conn = ctx->commit->conn;
- handler->session = ctx->commit->session;
-
- handler->response_handler = svn_ra_serf__expect_empty_body;
- handler->response_baton = handler;
-
- handler->header_delegate = setup_copy_file_headers;
- handler->header_delegate_baton = ctx;
-
- SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
-
- if (handler->sline.code != 201 && handler->sline.code != 204)
- {
- return svn_error_trace(return_response_err(handler));
- }
- }
-
/* If we got no stream of changes, but this is an added-without-history
* file, make a note that we'll be PUTting a zero-byte file to the server.
*/
- if ((!ctx->stream) && ctx->added && (!ctx->copy_path))
+ if ((!ctx->svndiff) && ctx->added && (!ctx->copy_path))
put_empty_file = TRUE;
/* If we had a stream of changes, push them to the server... */
- if (ctx->stream || put_empty_file)
+ if (ctx->svndiff || put_empty_file)
{
svn_ra_serf__handler_t *handler;
+ int expected_result;
+
+ handler = svn_ra_serf__create_handler(scratch_pool);
- handler = apr_pcalloc(scratch_pool, sizeof(*handler));
- handler->handler_pool = scratch_pool;
handler->method = "PUT";
handler->path = ctx->url;
- handler->conn = ctx->commit->conn;
- handler->session = ctx->commit->session;
+ handler->conn = ctx->commit_ctx->conn;
+ handler->session = ctx->commit_ctx->session;
handler->response_handler = svn_ra_serf__expect_empty_body;
handler->response_baton = handler;
@@ -2159,10 +2091,13 @@ close_file(void *file_baton,
SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
- if (handler->sline.code != 204 && handler->sline.code != 201)
- {
- return svn_error_trace(return_response_err(handler));
- }
+ if (ctx->added && ! ctx->copy_path)
+ expected_result = 201; /* Created */
+ else
+ expected_result = 204; /* Updated */
+
+ if (handler->sline.code != expected_result)
+ return svn_error_trace(svn_ra_serf__unexpected_status(handler));
}
if (ctx->svndiff)
@@ -2178,12 +2113,14 @@ close_file(void *file_baton,
proppatch->pool = scratch_pool;
proppatch->relpath = ctx->relpath;
proppatch->path = ctx->url;
- proppatch->commit = ctx->commit;
+ proppatch->commit_ctx = ctx->commit_ctx;
proppatch->changed_props = ctx->changed_props;
proppatch->removed_props = ctx->removed_props;
proppatch->base_revision = ctx->base_revision;
- SVN_ERR(proppatch_resource(proppatch, ctx->commit, scratch_pool));
+ SVN_ERR(proppatch_resource(ctx->commit_ctx->session,
+ ctx->commit_ctx->conn,
+ proppatch, scratch_pool));
}
return SVN_NO_ERROR;
@@ -2197,10 +2134,9 @@ close_edit(void *edit_baton,
const char *merge_target =
ctx->activity_url ? ctx->activity_url : ctx->txn_url;
const svn_commit_info_t *commit_info;
- int response_code;
/* MERGE our activity */
- SVN_ERR(svn_ra_serf__run_merge(&commit_info, &response_code,
+ SVN_ERR(svn_ra_serf__run_merge(&commit_info,
ctx->session,
ctx->session->conns[0],
merge_target,
@@ -2208,14 +2144,6 @@ close_edit(void *edit_baton,
ctx->keep_locks,
pool, pool));
- if (response_code != 200)
- {
- return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
- _("MERGE request failed: returned %d "
- "(during commit)"),
- response_code);
- }
-
/* Inform the WC that we did a commit. */
if (ctx->callback)
SVN_ERR(ctx->callback(commit_info, ctx->callback_baton, pool));
@@ -2225,8 +2153,8 @@ close_edit(void *edit_baton,
{
svn_ra_serf__handler_t *handler;
- handler = apr_pcalloc(pool, sizeof(*handler));
- handler->handler_pool = pool;
+ handler = svn_ra_serf__create_handler(pool);
+
handler->method = "DELETE";
handler->path = ctx->activity_url;
handler->conn = ctx->conn;
@@ -2235,9 +2163,12 @@ close_edit(void *edit_baton,
handler->response_handler = svn_ra_serf__expect_empty_body;
handler->response_baton = handler;
+ ctx->activity_url = NULL; /* Don't try again in abort_edit() on fail */
+
SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
- SVN_ERR_ASSERT(handler->sline.code == 204);
+ if (handler->sline.code != 204)
+ return svn_error_trace(svn_ra_serf__unexpected_status(handler));
}
return SVN_NO_ERROR;
@@ -2260,14 +2191,15 @@ abort_edit(void *edit_baton,
serf_connection_reset(ctx->session->conns[0]->conn);
/* DELETE our aborted activity */
- handler = apr_pcalloc(pool, sizeof(*handler));
- handler->handler_pool = pool;
+ handler = svn_ra_serf__create_handler(pool);
+
handler->method = "DELETE";
handler->conn = ctx->session->conns[0];
handler->session = ctx->session;
handler->response_handler = svn_ra_serf__expect_empty_body;
handler->response_baton = handler;
+ handler->no_fail_on_http_failure_status = TRUE;
if (USING_HTTPV2_COMMIT_SUPPORT(ctx)) /* HTTP v2 */
handler->path = ctx->txn_url;
@@ -2281,12 +2213,9 @@ abort_edit(void *edit_baton,
404 if the activity wasn't found. */
if (handler->sline.code != 204
&& handler->sline.code != 403
- && handler->sline.code != 404
- )
+ && handler->sline.code != 404)
{
- return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
- _("DELETE returned unexpected status: %d"),
- handler->sline.code);
+ return svn_error_trace(svn_ra_serf__unexpected_status(handler));
}
return SVN_NO_ERROR;
@@ -2337,7 +2266,8 @@ svn_ra_serf__get_commit_editor(svn_ra_se
ctx->callback = callback;
ctx->callback_baton = callback_baton;
- ctx->lock_tokens = lock_tokens;
+ ctx->lock_tokens = (lock_tokens && apr_hash_count(lock_tokens))
+ ? lock_tokens : NULL;
ctx->keep_locks = keep_locks;
ctx->deleted_entries = apr_hash_make(ctx->pool);
@@ -2381,28 +2311,43 @@ svn_ra_serf__change_rev_prop(svn_ra_sess
{
svn_ra_serf__session_t *session = ra_session->priv;
proppatch_context_t *proppatch_ctx;
- commit_context_t *commit;
const char *proppatch_target;
const char *ns;
+ const svn_string_t *tmp_old_value;
+ svn_boolean_t atomic_capable = FALSE;
svn_error_t *err;
+ if (old_value_p || !value)
+ SVN_ERR(svn_ra_serf__has_capability(ra_session, &atomic_capable,
+ SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
+ pool));
+
if (old_value_p)
{
- svn_boolean_t capable;
- SVN_ERR(svn_ra_serf__has_capability(ra_session, &capable,
- SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
- pool));
-
/* How did you get past the same check in svn_ra_change_rev_prop2()? */
- SVN_ERR_ASSERT(capable);
+ SVN_ERR_ASSERT(atomic_capable);
}
+ else if (! value && atomic_capable)
+ {
+ svn_string_t *old_value;
+ /* mod_dav_svn doesn't report a failure when a property delete fails. The
+ atomic revprop change behavior is a nice workaround, to allow getting
+ access to the error anyway.
- commit = apr_pcalloc(pool, sizeof(*commit));
+ Somehow the mod_dav maintainers think that returning an error from
+ mod_dav's property delete is an RFC violation.
+ See https://issues.apache.org/bugzilla/show_bug.cgi?id=53525 */
- commit->pool = pool;
+ SVN_ERR(svn_ra_serf__rev_prop(ra_session, rev, name, &old_value,
+ pool));
- commit->session = session;
- commit->conn = session->conns[0];
+ if (!old_value)
+ return SVN_NO_ERROR; /* Nothing to delete */
+
+ /* The api expects a double const pointer. Let's make one */
+ tmp_old_value = old_value;
+ old_value_p = &tmp_old_value;
+ }
if (SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(session))
{
@@ -2412,11 +2357,11 @@ svn_ra_serf__change_rev_prop(svn_ra_sess
{
const char *vcc_url;
- SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, commit->session,
- commit->conn, pool));
+ SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, session,
+ session->conns[0], pool));
SVN_ERR(svn_ra_serf__fetch_dav_prop(&proppatch_target,
- commit->conn, vcc_url, rev,
+ session->conns[0], vcc_url, rev,
"href",
pool, pool));
}
@@ -2434,14 +2379,14 @@ svn_ra_serf__change_rev_prop(svn_ra_sess
/* PROPPATCH our log message and pass it along. */
proppatch_ctx = apr_pcalloc(pool, sizeof(*proppatch_ctx));
proppatch_ctx->pool = pool;
- proppatch_ctx->commit = commit;
+ proppatch_ctx->commit_ctx = NULL; /* No lock headers */
proppatch_ctx->path = proppatch_target;
- proppatch_ctx->changed_props = apr_hash_make(proppatch_ctx->pool);
- proppatch_ctx->removed_props = apr_hash_make(proppatch_ctx->pool);
+ proppatch_ctx->changed_props = apr_hash_make(pool);
+ proppatch_ctx->removed_props = apr_hash_make(pool);
if (old_value_p)
{
- proppatch_ctx->previous_changed_props = apr_hash_make(proppatch_ctx->pool);
- proppatch_ctx->previous_removed_props = apr_hash_make(proppatch_ctx->pool);
+ proppatch_ctx->previous_changed_props = apr_hash_make(pool);
+ proppatch_ctx->previous_removed_props = apr_hash_make(pool);
}
proppatch_ctx->base_revision = SVN_INVALID_REVNUM;
@@ -2449,37 +2394,46 @@ svn_ra_serf__change_rev_prop(svn_ra_sess
{
svn_ra_serf__set_prop(proppatch_ctx->previous_changed_props,
proppatch_ctx->path,
- ns, name, *old_value_p, proppatch_ctx->pool);
+ ns, name, *old_value_p, pool);
}
else if (old_value_p)
{
- svn_string_t *dummy_value = svn_string_create_empty(proppatch_ctx->pool);
+ svn_string_t *dummy_value = svn_string_create_empty(pool);
svn_ra_serf__set_prop(proppatch_ctx->previous_removed_props,
proppatch_ctx->path,
- ns, name, dummy_value, proppatch_ctx->pool);
+ ns, name, dummy_value, pool);
}
if (value)
{
svn_ra_serf__set_prop(proppatch_ctx->changed_props, proppatch_ctx->path,
- ns, name, value, proppatch_ctx->pool);
+ ns, name, value, pool);
}
else
{
- value = svn_string_create_empty(proppatch_ctx->pool);
+ value = svn_string_create_empty(pool);
svn_ra_serf__set_prop(proppatch_ctx->removed_props, proppatch_ctx->path,
- ns, name, value, proppatch_ctx->pool);
+ ns, name, value, pool);
}
- err = proppatch_resource(proppatch_ctx, commit, proppatch_ctx->pool);
- if (err)
- return
- svn_error_create
- (SVN_ERR_RA_DAV_REQUEST_FAILED, err,
- _("DAV request failed; it's possible that the repository's "
- "pre-revprop-change hook either failed or is non-existent"));
+ err = proppatch_resource(session,
+ session->conns[0],
+ proppatch_ctx, pool);
- return SVN_NO_ERROR;
+ /* Use specific error code for old property value mismatch.
+ Use loop to provide the right result with tracing */
+ if (err && err->apr_err == SVN_ERR_RA_DAV_PRECONDITION_FAILED)
+ {
+ svn_error_t *e = err;
+
+ while (e && e->apr_err == SVN_ERR_RA_DAV_PRECONDITION_FAILED)
+ {
+ e->apr_err = SVN_ERR_FS_PROP_BASEVALUE_MISMATCH;
+ e = e->child;
+ }
+ }
+
+ return svn_error_trace(err);
}
Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/get_deleted_rev.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/get_deleted_rev.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/get_deleted_rev.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/get_deleted_rev.c Thu Jan 9 09:31:10 2014
@@ -151,7 +151,7 @@ svn_ra_serf__get_deleted_rev(svn_ra_sess
pool, pool));
xmlctx = svn_ra_serf__xml_context_create(getdrev_ttable,
- NULL, getdrev_closed, NULL, NULL,
+ NULL, getdrev_closed, NULL,
drev_ctx,
pool);
handler = svn_ra_serf__create_expat_handler(xmlctx, NULL, pool);
Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getdate.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getdate.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getdate.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getdate.c Thu Jan 9 09:31:10 2014
@@ -131,7 +131,6 @@ svn_ra_serf__get_dated_revision(svn_ra_s
svn_ra_serf__handler_t *handler;
svn_ra_serf__xml_context_t *xmlctx;
const char *report_target;
- svn_error_t *err;
date_ctx = apr_palloc(pool, sizeof(*date_ctx));
date_ctx->time = tm;
@@ -140,7 +139,7 @@ svn_ra_serf__get_dated_revision(svn_ra_s
SVN_ERR(svn_ra_serf__report_resource(&report_target, session, NULL, pool));
xmlctx = svn_ra_serf__xml_context_create(date_ttable,
- NULL, date_closed, NULL, NULL,
+ NULL, date_closed, NULL,
date_ctx,
pool);
handler = svn_ra_serf__create_expat_handler(xmlctx, NULL, pool);
@@ -156,13 +155,11 @@ svn_ra_serf__get_dated_revision(svn_ra_s
*date_ctx->revision = SVN_INVALID_REVNUM;
- err = svn_ra_serf__context_run_one(handler, pool);
+ SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
- SVN_ERR(svn_error_compose_create(
- svn_ra_serf__error_on_status(handler->sline,
- report_target,
- handler->location),
- err));
+ SVN_ERR(svn_ra_serf__error_on_status(handler->sline,
+ report_target,
+ handler->location));
SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(*revision));
Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getlocations.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getlocations.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getlocations.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getlocations.c Thu Jan 9 09:31:10 2014
@@ -159,7 +159,6 @@ svn_ra_serf__get_locations(svn_ra_sessio
svn_ra_serf__handler_t *handler;
svn_ra_serf__xml_context_t *xmlctx;
const char *req_url;
- svn_error_t *err;
loc_ctx = apr_pcalloc(pool, sizeof(*loc_ctx));
loc_ctx->pool = pool;
@@ -176,7 +175,7 @@ svn_ra_serf__get_locations(svn_ra_sessio
pool, pool));
xmlctx = svn_ra_serf__xml_context_create(getloc_ttable,
- NULL, getloc_closed, NULL, NULL,
+ NULL, getloc_closed, NULL,
loc_ctx,
pool);
handler = svn_ra_serf__create_expat_handler(xmlctx, NULL, pool);
@@ -189,13 +188,11 @@ svn_ra_serf__get_locations(svn_ra_sessio
handler->conn = session->conns[0];
handler->session = session;
- err = svn_ra_serf__context_run_one(handler, pool);
+ SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
- SVN_ERR(svn_error_compose_create(
- svn_ra_serf__error_on_status(handler->sline,
- req_url,
- handler->location),
- err));
+ SVN_ERR(svn_ra_serf__error_on_status(handler->sline,
+ handler->path,
+ handler->location));
return SVN_NO_ERROR;
}
Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getlocationsegments.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getlocationsegments.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getlocationsegments.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getlocationsegments.c Thu Jan 9 09:31:10 2014
@@ -178,7 +178,7 @@ svn_ra_serf__get_location_segments(svn_r
pool, pool));
xmlctx = svn_ra_serf__xml_context_create(gls_ttable,
- NULL, gls_closed, NULL, NULL,
+ NULL, gls_closed, NULL,
gls_ctx,
pool);
handler = svn_ra_serf__create_expat_handler(xmlctx, NULL, pool);
@@ -193,11 +193,12 @@ svn_ra_serf__get_location_segments(svn_r
err = svn_ra_serf__context_run_one(handler, pool);
- err = svn_error_compose_create(
- svn_ra_serf__error_on_status(handler->sline,
- handler->path,
- handler->location),
- err);
+ if (!err)
+ {
+ err = svn_ra_serf__error_on_status(handler->sline,
+ handler->path,
+ handler->location);
+ }
if (err && (err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE))
return svn_error_create(SVN_ERR_RA_NOT_IMPLEMENTED, err, NULL);
Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getlocks.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getlocks.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getlocks.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getlocks.c Thu Jan 9 09:31:10 2014
@@ -246,7 +246,7 @@ svn_ra_serf__get_locks(svn_ra_session_t
lock_ctx->hash = apr_hash_make(pool);
xmlctx = svn_ra_serf__xml_context_create(getlocks_ttable,
- NULL, getlocks_closed, NULL, NULL,
+ NULL, getlocks_closed, NULL,
lock_ctx,
pool);
handler = svn_ra_serf__create_expat_handler(xmlctx, NULL, pool);
@@ -259,16 +259,22 @@ svn_ra_serf__get_locks(svn_ra_session_t
handler->body_delegate = create_getlocks_body;
handler->body_delegate_baton = lock_ctx;
+ handler->no_fail_on_http_failure_status = TRUE;
SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
/* We get a 404 when a path doesn't exist in HEAD, but it might
have existed earlier (E.g. 'svn ls http://s/svn/trunk/file@1' */
- if (handler->sline.code != 404)
+ if (handler->sline.code != 200
+ && handler->sline.code != 404)
{
- SVN_ERR(svn_ra_serf__error_on_status(handler->sline,
- handler->path,
- handler->location));
+ svn_error_t *err = svn_ra_serf__unexpected_status(handler);
+
+ if (handler->sline.code == 500 || handler->sline.code == 501)
+ return svn_error_create(SVN_ERR_RA_NOT_IMPLEMENTED, err,
+ _("Server does not support locking features"));
+
+ return svn_error_trace(err);
}
*locks = lock_ctx->hash;
Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/inherited_props.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/inherited_props.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/inherited_props.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/inherited_props.c Thu Jan 9 09:31:10 2014
@@ -29,12 +29,14 @@
#include "svn_hash.h"
#include "svn_path.h"
#include "svn_ra.h"
+#include "svn_sorts.h"
#include "svn_string.h"
#include "svn_xml.h"
#include "svn_props.h"
#include "svn_base64.h"
#include "private/svn_dav_protocol.h"
+#include "private/svn_sorts_private.h"
#include "../libsvn_ra/ra_loader.h"
#include "ra_serf.h"
@@ -220,6 +222,155 @@ create_iprops_body(serf_bucket_t **bkt,
return SVN_NO_ERROR;
}
+/* Per request information for get_iprops_via_more_requests */
+typedef struct iprop_rq_info_t
+{
+ const char *relpath;
+ const char *urlpath;
+ apr_hash_t *props;
+ svn_ra_serf__handler_t *handler;
+} iprop_rq_info_t;
+
+/* Removes all non regular properties from PROPS */
+static void
+keep_only_regular_props(apr_hash_t *props,
+ apr_pool_t *scratch_pool)
+{
+ apr_hash_index_t *hi;
+
+ for (hi = apr_hash_first(scratch_pool, props); hi; hi = apr_hash_next(hi))
+ {
+ const char *propname = svn__apr_hash_index_key(hi);
+
+ if (svn_property_kind2(propname) != svn_prop_regular_kind)
+ svn_hash_sets(props, propname, NULL);
+ }
+}
+
+/* Assumes session reparented to the repository root. The old session
+ root is passed as session_url */
+static svn_error_t *
+get_iprops_via_more_requests(svn_ra_session_t *ra_session,
+ apr_array_header_t **iprops,
+ const char *session_url,
+ const char *path,
+ svn_revnum_t revision,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_ra_serf__session_t *session = ra_session->priv;
+ const char *url;
+ const char *relpath;
+ apr_array_header_t *rq_info;
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ apr_interval_time_t waittime_left = session->timeout;
+ const svn_revnum_t rev_marker = SVN_INVALID_REVNUM;
+ int i;
+
+ rq_info = apr_array_make(scratch_pool, 16, sizeof(iprop_rq_info_t *));
+
+ if (!svn_path_is_empty(path))
+ url = svn_path_url_add_component2(session_url, path, scratch_pool);
+ else
+ url = session_url;
+
+ relpath = svn_uri_skip_ancestor(session->repos_root_str, url, scratch_pool);
+
+ /* Create all requests */
+ while (relpath[0] != '\0')
+ {
+ iprop_rq_info_t *rq = apr_pcalloc(scratch_pool, sizeof(*rq));
+
+ relpath = svn_relpath_dirname(relpath, scratch_pool);
+
+ rq->relpath = relpath;
+ rq->props = apr_hash_make(scratch_pool);
+
+ SVN_ERR(svn_ra_serf__get_stable_url(&rq->urlpath, NULL, session,
+ session->conns[0],
+ svn_path_url_add_component2(
+ session->repos_root.path,
+ relpath, scratch_pool),
+ revision,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR(svn_ra_serf__deliver_props(&rq->handler, rq->props, session,
+ session->conns[0], rq->urlpath,
+ rev_marker, "0", all_props,
+ NULL, scratch_pool));
+
+ /* Allow ignoring authz problems */
+ rq->handler->no_fail_on_http_failure_status = TRUE;
+
+ svn_ra_serf__request_create(rq->handler);
+
+ APR_ARRAY_PUSH(rq_info, iprop_rq_info_t *) = rq;
+ }
+
+ while (TRUE)
+ {
+ svn_pool_clear(iterpool);
+
+ SVN_ERR(svn_ra_serf__context_run(session, &waittime_left, iterpool));
+
+ for (i = 0; i < rq_info->nelts; i++)
+ {
+ iprop_rq_info_t *rq = APR_ARRAY_IDX(rq_info, i, iprop_rq_info_t *);
+
+ if (!rq->handler->done)
+ break;
+ }
+
+ if (i >= rq_info->nelts)
+ break; /* All requests done */
+ }
+
+ *iprops = apr_array_make(result_pool, rq_info->nelts,
+ sizeof(svn_prop_inherited_item_t *));
+
+ /* And now create the result set */
+ for (i = 0; i < rq_info->nelts; i++)
+ {
+ iprop_rq_info_t *rq = APR_ARRAY_IDX(rq_info, i, iprop_rq_info_t *);
+ apr_hash_t *node_props;
+ svn_prop_inherited_item_t *new_iprop;
+
+ if (rq->handler->sline.code >= 400 && rq->handler->sline.code != 403)
+ {
+ return svn_error_trace(
+ svn_ra_serf__error_on_status(rq->handler->sline,
+ rq->handler->path,
+ rq->handler->location));
+ }
+
+ /* Obtain the real properties from the double hash */
+ node_props = apr_hash_get(rq->props, &rev_marker, sizeof(rev_marker));
+
+ if (!node_props)
+ continue;
+
+ node_props = svn_hash_gets(node_props, rq->urlpath);
+
+ if (!node_props)
+ continue;
+
+ SVN_ERR(svn_ra_serf__flatten_props(&node_props, node_props,
+ scratch_pool, scratch_pool));
+
+ keep_only_regular_props(node_props, scratch_pool);
+
+ if (!apr_hash_count(node_props))
+ continue;
+
+ new_iprop = apr_palloc(result_pool, sizeof(*new_iprop));
+ new_iprop->path_or_url = apr_pstrdup(result_pool, rq->relpath);
+ new_iprop->prop_hash = svn_prop_hash_dup(node_props, result_pool);
+ svn_sort__array_insert(*iprops, &new_iprop, 0);
+ }
+
+ return SVN_NO_ERROR;
+}
+
/* Request a inherited-props-report from the URL attached to RA_SESSION,
and fill the IPROPS array hash with the results. */
svn_error_t *
@@ -230,12 +381,47 @@ svn_ra_serf__get_inherited_props(svn_ra_
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- svn_error_t *err;
iprops_context_t *iprops_ctx;
svn_ra_serf__session_t *session = ra_session->priv;
svn_ra_serf__handler_t *handler;
svn_ra_serf__xml_context_t *xmlctx;
const char *req_url;
+ svn_boolean_t iprop_capable;
+
+ SVN_ERR(svn_ra_serf__has_capability(ra_session, &iprop_capable,
+ SVN_RA_CAPABILITY_INHERITED_PROPS,
+ scratch_pool));
+
+ if (!iprop_capable)
+ {
+ svn_error_t *err;
+ const char *reparent_uri = NULL;
+ const char *session_uri;
+ const char *repos_root_url;
+
+ SVN_ERR(svn_ra_serf__get_repos_root(ra_session, &repos_root_url,
+ scratch_pool));
+
+ session_uri = apr_pstrdup(scratch_pool, session->session_url_str);
+ if (strcmp(repos_root_url, session->session_url_str) != 0)
+ {
+ reparent_uri = session_uri;
+ SVN_ERR(svn_ra_serf__reparent(ra_session, repos_root_url,
+ scratch_pool));
+ }
+
+ /* For now, use implementation in libsvn_ra */
+ err = get_iprops_via_more_requests(ra_session, iprops, session_uri, path,
+ revision, result_pool, scratch_pool);
+
+ if (reparent_uri)
+ err = svn_error_compose_create(err,
+ svn_ra_serf__reparent(ra_session,
+ reparent_uri ,
+ scratch_pool));
+
+ return svn_error_trace(err);
+ }
SVN_ERR(svn_ra_serf__get_stable_url(&req_url,
NULL /* latest_revnum */,
@@ -259,7 +445,7 @@ svn_ra_serf__get_inherited_props(svn_ra_
xmlctx = svn_ra_serf__xml_context_create(iprops_table,
iprops_opened, iprops_closed,
- NULL, NULL,
+ NULL,
iprops_ctx,
scratch_pool);
handler = svn_ra_serf__create_expat_handler(xmlctx, NULL, scratch_pool);
@@ -271,14 +457,11 @@ svn_ra_serf__get_inherited_props(svn_ra_
handler->body_delegate = create_iprops_body;
handler->body_delegate_baton = iprops_ctx;
handler->body_type = "text/xml";
- handler->handler_pool = scratch_pool;
- err = svn_ra_serf__context_run_one(handler, scratch_pool);
- SVN_ERR(svn_error_compose_create(
- svn_ra_serf__error_on_status(handler->sline,
- handler->path,
- handler->location),
- err));
+ SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
+
+ if (handler->sline.code != 200)
+ return svn_error_trace(svn_ra_serf__unexpected_status(handler));
*iprops = iprops_ctx->iprops;
Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/log.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/log.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/log.c Thu Jan 9 09:31:10 2014
@@ -542,7 +542,6 @@ svn_ra_serf__get_log(svn_ra_session_t *r
svn_ra_serf__xml_context_t *xmlctx;
svn_boolean_t want_custom_revprops;
svn_revnum_t peg_rev;
- svn_error_t *err;
const char *req_url;
log_ctx = apr_pcalloc(pool, sizeof(*log_ctx));
@@ -604,7 +603,7 @@ svn_ra_serf__get_log(svn_ra_session_t *r
pool, pool));
xmlctx = svn_ra_serf__xml_context_create(log_ttable,
- log_opened, log_closed, NULL, NULL,
+ log_opened, log_closed, NULL,
log_ctx,
pool);
handler = svn_ra_serf__create_expat_handler(xmlctx, NULL, pool);
@@ -617,13 +616,10 @@ svn_ra_serf__get_log(svn_ra_session_t *r
handler->conn = session->conns[0];
handler->session = session;
- err = svn_ra_serf__context_run_one(handler, pool);
+ SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
- SVN_ERR(svn_error_compose_create(
+ return svn_error_trace(
svn_ra_serf__error_on_status(handler->sline,
req_url,
- handler->location),
- err));
-
- return SVN_NO_ERROR;
+ handler->location));
}
Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/merge.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/merge.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/merge.c Thu Jan 9 09:31:10 2014
@@ -65,7 +65,7 @@ typedef enum merge_state_e {
AUTHOR,
POST_COMMIT_ERR,
- PROP_VAL
+ STATUS
} merge_state_e;
@@ -279,12 +279,12 @@ setup_merge_headers(serf_bucket_t *heade
return SVN_NO_ERROR;
}
-void
-svn_ra_serf__merge_lock_token_list(apr_hash_t *lock_tokens,
- const char *parent,
- serf_bucket_t *body,
- serf_bucket_alloc_t *alloc,
- apr_pool_t *pool)
+static void
+merge_lock_token_list(apr_hash_t *lock_tokens,
+ const char *parent,
+ serf_bucket_t *body,
+ serf_bucket_alloc_t *alloc,
+ apr_pool_t *pool)
{
apr_hash_index_t *hi;
@@ -363,8 +363,7 @@ create_merge_body(serf_bucket_t **bkt,
svn_ra_serf__add_tag_buckets(body_bkt, "D:creator-displayname", NULL, alloc);
svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, "D:prop");
- svn_ra_serf__merge_lock_token_list(ctx->lock_tokens, NULL, body_bkt, alloc,
- pool);
+ merge_lock_token_list(ctx->lock_tokens, NULL, body_bkt, alloc, pool);
svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, "D:merge");
@@ -376,7 +375,6 @@ create_merge_body(serf_bucket_t **bkt,
svn_error_t *
svn_ra_serf__run_merge(const svn_commit_info_t **commit_info,
- int *response_code,
svn_ra_serf__session_t *session,
svn_ra_serf__connection_t *conn,
const char *merge_resource_url,
@@ -404,7 +402,7 @@ svn_ra_serf__run_merge(const svn_commit_
merge_ctx->merge_url = session->session_url.path;
xmlctx = svn_ra_serf__xml_context_create(merge_ttable,
- NULL, merge_closed, NULL, NULL,
+ NULL, merge_closed, NULL,
merge_ctx,
scratch_pool);
handler = svn_ra_serf__create_expat_handler(xmlctx, NULL, scratch_pool);
@@ -423,8 +421,10 @@ svn_ra_serf__run_merge(const svn_commit_
SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
+ if (handler->sline.code != 200)
+ return svn_error_trace(svn_ra_serf__unexpected_status(handler));
+
*commit_info = merge_ctx->commit_info;
- *response_code = handler->sline.code;
return SVN_NO_ERROR;
}
Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/mergeinfo.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/mergeinfo.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/mergeinfo.c Thu Jan 9 09:31:10 2014
@@ -191,7 +191,6 @@ svn_ra_serf__get_mergeinfo(svn_ra_sessio
svn_boolean_t include_descendants,
apr_pool_t *pool)
{
- svn_error_t *err;
mergeinfo_context_t *mergeinfo_ctx;
svn_ra_serf__session_t *session = ra_session->priv;
svn_ra_serf__handler_t *handler;
@@ -214,7 +213,7 @@ svn_ra_serf__get_mergeinfo(svn_ra_sessio
mergeinfo_ctx->include_descendants = include_descendants;
xmlctx = svn_ra_serf__xml_context_create(mergeinfo_ttable,
- NULL, mergeinfo_closed, NULL, NULL,
+ NULL, mergeinfo_closed, NULL,
mergeinfo_ctx,
pool);
handler = svn_ra_serf__create_expat_handler(xmlctx, NULL, pool);
@@ -227,14 +226,12 @@ svn_ra_serf__get_mergeinfo(svn_ra_sessio
handler->body_delegate_baton = mergeinfo_ctx;
handler->body_type = "text/xml";
- err = svn_ra_serf__context_run_one(handler, pool);
+ SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
- SVN_ERR(svn_error_compose_create(
- svn_ra_serf__error_on_status(handler->sline, handler->path,
- handler->location),
- err));
+ SVN_ERR(svn_ra_serf__error_on_status(handler->sline, handler->path,
+ handler->location));
- if (handler->done && apr_hash_count(mergeinfo_ctx->result_catalog))
+ if (apr_hash_count(mergeinfo_ctx->result_catalog))
*catalog = mergeinfo_ctx->result_catalog;
return SVN_NO_ERROR;