diff options
| author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2015-03-18 13:33:26 +0000 |
|---|---|---|
| committer | <> | 2015-07-08 14:41:01 +0000 |
| commit | bb0ef45f7c46b0ae221b26265ef98a768c33f820 (patch) | |
| tree | 98bae10dde41c746c51ae97ec4f879e330415aa7 /subversion/libsvn_ra | |
| parent | 239dfafe71711b2f4c43d7b90a1228d7bdc5195e (diff) | |
| download | subversion-tarball-bb0ef45f7c46b0ae221b26265ef98a768c33f820.tar.gz | |
Imported from /home/lorry/working-area/delta_subversion-tarball/subversion-1.8.13.tar.gz.subversion-1.8.13
Diffstat (limited to 'subversion/libsvn_ra')
| -rw-r--r-- | subversion/libsvn_ra/compat.c | 114 | ||||
| -rw-r--r-- | subversion/libsvn_ra/debug_reporter.c | 4 | ||||
| -rw-r--r-- | subversion/libsvn_ra/deprecated.c | 108 | ||||
| -rw-r--r-- | subversion/libsvn_ra/deprecated.h | 60 | ||||
| -rw-r--r-- | subversion/libsvn_ra/editor.c | 339 | ||||
| -rw-r--r-- | subversion/libsvn_ra/ra_loader.c | 503 | ||||
| -rw-r--r-- | subversion/libsvn_ra/ra_loader.h | 122 | ||||
| -rw-r--r-- | subversion/libsvn_ra/util.c | 62 | ||||
| -rw-r--r-- | subversion/libsvn_ra/wrapper_template.h | 12 |
9 files changed, 1109 insertions, 215 deletions
diff --git a/subversion/libsvn_ra/compat.c b/subversion/libsvn_ra/compat.c index ec3ff9d..b16bbef 100644 --- a/subversion/libsvn_ra/compat.c +++ b/subversion/libsvn_ra/compat.c @@ -23,6 +23,7 @@ #include <apr_pools.h> +#include "svn_hash.h" #include "svn_error.h" #include "svn_pools.h" #include "svn_sorts.h" @@ -91,7 +92,7 @@ prev_log_path(const char **prev_path_p, if (changed_paths) { /* See if PATH was explicitly changed in this revision. */ - change = apr_hash_get(changed_paths, path, APR_HASH_KEY_STRING); + change = svn_hash_gets(changed_paths, path); if (change) { /* If PATH was not newly added in this revision, then it may or may @@ -141,7 +142,7 @@ prev_log_path(const char **prev_path_p, svn_sort__item_t item = APR_ARRAY_IDX(paths, i - 1, svn_sort__item_t); const char *ch_path = item.key; - int len = strlen(ch_path); + size_t len = strlen(ch_path); /* See if our path is the child of this change path. If not, keep looking. */ @@ -154,7 +155,7 @@ prev_log_path(const char **prev_path_p, path, to the change's copyfrom path. Otherwise, this change isn't really interesting to us, and our search continues. */ - change = apr_hash_get(changed_paths, ch_path, len); + change = item.value; if (change->copyfrom_path) { if (action_p) @@ -630,7 +631,6 @@ fr_log_message_receiver(void *baton, { struct fr_log_message_baton *lmb = baton; struct rev *rev; - apr_hash_index_t *hi; rev = apr_palloc(lmb->pool, sizeof(*rev)); rev->revision = log_entry->revision; @@ -639,17 +639,7 @@ fr_log_message_receiver(void *baton, lmb->eldest = rev; /* Duplicate log_entry revprops into rev->props */ - rev->props = apr_hash_make(lmb->pool); - for (hi = apr_hash_first(pool, log_entry->revprops); hi; - hi = apr_hash_next(hi)) - { - void *val; - const void *key; - - apr_hash_this(hi, &key, NULL, &val); - apr_hash_set(rev->props, apr_pstrdup(lmb->pool, key), APR_HASH_KEY_STRING, - svn_string_dup(val, lmb->pool)); - } + rev->props = svn_prop_hash_dup(log_entry->revprops, lmb->pool); return prev_log_path(&lmb->path, &lmb->action, &lmb->copyrev, log_entry->changed_paths2, @@ -757,8 +747,9 @@ svn_ra__file_revs_from_log(svn_ra_session_t *ra_session, /* Compute and send delta if client asked for it. */ if (delta_handler) { - /* Get the content delta. */ - svn_txdelta(&delta_stream, last_stream, stream, lastpool); + /* Get the content delta. Don't calculate checksums as we don't + * use them. */ + svn_txdelta2(&delta_stream, last_stream, stream, FALSE, lastpool); /* And send. */ SVN_ERR(svn_txdelta_send_txstream(delta_stream, delta_handler, @@ -870,3 +861,92 @@ svn_ra__get_deleted_rev_from_log(svn_ra_session_t *session, *revision_deleted = log_path_deleted_baton.revision_deleted; return SVN_NO_ERROR; } + + +svn_error_t * +svn_ra__get_inherited_props_walk(svn_ra_session_t *session, + const char *path, + svn_revnum_t revision, + apr_array_header_t **inherited_props, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + const char *repos_root_url; + const char *session_url; + const char *parent_url; + apr_pool_t *iterpool = svn_pool_create(scratch_pool); + + *inherited_props = + apr_array_make(result_pool, 1, sizeof(svn_prop_inherited_item_t *)); + + /* Walk to the root of the repository getting inherited + props for PATH. */ + SVN_ERR(svn_ra_get_repos_root2(session, &repos_root_url, scratch_pool)); + SVN_ERR(svn_ra_get_session_url(session, &session_url, scratch_pool)); + parent_url = session_url; + + while (strcmp(repos_root_url, parent_url)) + { + apr_hash_index_t *hi; + apr_hash_t *parent_props; + apr_hash_t *final_hash = apr_hash_make(result_pool); + svn_error_t *err; + + svn_pool_clear(iterpool); + parent_url = svn_uri_dirname(parent_url, scratch_pool); + SVN_ERR(svn_ra_reparent(session, parent_url, iterpool)); + err = session->vtable->get_dir(session, NULL, NULL, + &parent_props, "", + revision, SVN_DIRENT_ALL, + iterpool); + + /* If the user doesn't have read access to a parent path then + skip, but allow them to inherit from further up. */ + if (err) + { + if ((err->apr_err == SVN_ERR_RA_NOT_AUTHORIZED) + || (err->apr_err == SVN_ERR_RA_DAV_FORBIDDEN)) + { + svn_error_clear(err); + continue; + } + else + { + return svn_error_trace(err); + } + } + + for (hi = apr_hash_first(scratch_pool, parent_props); + hi; + hi = apr_hash_next(hi)) + { + const char *name = svn__apr_hash_index_key(hi); + apr_ssize_t klen = svn__apr_hash_index_klen(hi); + svn_string_t *value = svn__apr_hash_index_val(hi); + + if (svn_property_kind2(name) == svn_prop_regular_kind) + { + name = apr_pstrdup(result_pool, name); + value = svn_string_dup(value, result_pool); + apr_hash_set(final_hash, name, klen, value); + } + } + + if (apr_hash_count(final_hash)) + { + svn_prop_inherited_item_t *new_iprop = + apr_palloc(result_pool, sizeof(*new_iprop)); + new_iprop->path_or_url = svn_uri_skip_ancestor(repos_root_url, + parent_url, + result_pool); + new_iprop->prop_hash = final_hash; + svn_sort__array_insert(&new_iprop, *inherited_props, 0); + } + } + + /* Reparent session back to original URL. */ + SVN_ERR(svn_ra_reparent(session, session_url, scratch_pool)); + + svn_pool_destroy(iterpool); + return SVN_NO_ERROR; +} diff --git a/subversion/libsvn_ra/debug_reporter.c b/subversion/libsvn_ra/debug_reporter.c index 56248ac..00ec029 100644 --- a/subversion/libsvn_ra/debug_reporter.c +++ b/subversion/libsvn_ra/debug_reporter.c @@ -95,7 +95,7 @@ finish_report(void *report_baton, apr_pool_t *pool) { struct report_baton *rb = report_baton; - SVN_ERR(svn_stream_printf(rb->out, pool, "finish_report()\n")); + SVN_ERR(svn_stream_puts(rb->out, "finish_report()\n")); SVN_ERR(rb->wrapped_reporter->finish_report(rb->wrapped_report_baton, pool)); return SVN_NO_ERROR; } @@ -105,7 +105,7 @@ abort_report(void *report_baton, apr_pool_t *pool) { struct report_baton *rb = report_baton; - SVN_ERR(svn_stream_printf(rb->out, pool, "abort_report()\n")); + SVN_ERR(svn_stream_puts(rb->out, "abort_report()\n")); SVN_ERR(rb->wrapped_reporter->abort_report(rb->wrapped_report_baton, pool)); return SVN_NO_ERROR; } diff --git a/subversion/libsvn_ra/deprecated.c b/subversion/libsvn_ra/deprecated.c index 6fd2442..b7e717e 100644 --- a/subversion/libsvn_ra/deprecated.c +++ b/subversion/libsvn_ra/deprecated.c @@ -26,6 +26,7 @@ deprecated functions in this file. */ #define SVN_DEPRECATED +#include "svn_hash.h" #include "svn_ra.h" #include "svn_path.h" #include "svn_compat.h" @@ -33,6 +34,7 @@ #include "svn_pools.h" #include "ra_loader.h" +#include "deprecated.h" #include "svn_private_config.h" @@ -209,19 +211,18 @@ svn_error_t *svn_ra_get_commit_editor2(svn_ra_session_t *session, const svn_delta_editor_t **editor, void **edit_baton, const char *log_msg, - svn_commit_callback2_t callback, - void *callback_baton, + svn_commit_callback2_t commit_callback, + void *commit_baton, apr_hash_t *lock_tokens, svn_boolean_t keep_locks, apr_pool_t *pool) { apr_hash_t *revprop_table = apr_hash_make(pool); if (log_msg) - apr_hash_set(revprop_table, SVN_PROP_REVISION_LOG, - APR_HASH_KEY_STRING, - svn_string_create(log_msg, pool)); + svn_hash_sets(revprop_table, SVN_PROP_REVISION_LOG, + svn_string_create(log_msg, pool)); return svn_ra_get_commit_editor3(session, editor, edit_baton, revprop_table, - callback, callback_baton, + commit_callback, commit_baton, lock_tokens, keep_locks, pool); } @@ -348,6 +349,29 @@ svn_error_t *svn_ra_get_file_revs(svn_ra_session_t *session, handler2_baton, pool); } +svn_error_t * +svn_ra_do_update2(svn_ra_session_t *session, + const svn_ra_reporter3_t **reporter, + void **report_baton, + svn_revnum_t revision_to_update_to, + const char *update_target, + svn_depth_t depth, + svn_boolean_t send_copyfrom_args, + const svn_delta_editor_t *update_editor, + void *update_baton, + apr_pool_t *pool) +{ + return svn_error_trace( + svn_ra_do_update3(session, + reporter, report_baton, + revision_to_update_to, update_target, + depth, + send_copyfrom_args, + FALSE /* ignore_ancestry */, + update_editor, update_baton, + pool, pool)); +} + svn_error_t *svn_ra_do_update(svn_ra_session_t *session, const svn_ra_reporter2_t **reporter, void **report_baton, @@ -368,8 +392,34 @@ svn_error_t *svn_ra_do_update(svn_ra_session_t *session, revision_to_update_to, update_target, SVN_DEPTH_INFINITY_OR_FILES(recurse), FALSE, /* no copyfrom args */ + FALSE /* ignore_ancestry */, update_editor, update_baton, - pool); + pool, pool); +} + + +svn_error_t * +svn_ra_do_switch2(svn_ra_session_t *session, + const svn_ra_reporter3_t **reporter, + void **report_baton, + svn_revnum_t revision_to_switch_to, + const char *switch_target, + svn_depth_t depth, + const char *switch_url, + const svn_delta_editor_t *switch_editor, + void *switch_baton, + apr_pool_t *pool) +{ + return svn_error_trace( + svn_ra_do_switch3(session, + reporter, report_baton, + revision_to_switch_to, switch_target, + depth, + switch_url, + FALSE /* send_copyfrom_args */, + TRUE /* ignore_ancestry */, + switch_editor, switch_baton, + pool, pool)); } svn_error_t *svn_ra_do_switch(svn_ra_session_t *session, @@ -392,8 +442,11 @@ svn_error_t *svn_ra_do_switch(svn_ra_session_t *session, &(b->reporter3), &(b->reporter3_baton), revision_to_switch_to, switch_target, SVN_DEPTH_INFINITY_OR_FILES(recurse), - switch_url, switch_editor, switch_baton, - pool); + switch_url, + FALSE /* send_copyfrom_args */, + TRUE /* ignore_ancestry */, + switch_editor, switch_baton, + pool, pool); } svn_error_t *svn_ra_do_status(svn_ra_session_t *session, @@ -417,3 +470,40 @@ svn_error_t *svn_ra_do_status(svn_ra_session_t *session, SVN_DEPTH_INFINITY_OR_IMMEDIATES(recurse), status_editor, status_baton, pool); } + +svn_error_t *svn_ra_get_dir(svn_ra_session_t *session, + const char *path, + svn_revnum_t revision, + apr_hash_t **dirents, + svn_revnum_t *fetched_rev, + apr_hash_t **props, + apr_pool_t *pool) +{ + SVN_ERR_ASSERT(*path != '/'); + return session->vtable->get_dir(session, dirents, fetched_rev, props, + path, revision, SVN_DIRENT_ALL, pool); +} + +svn_error_t * +svn_ra_local__deprecated_init(int abi_version, + apr_pool_t *pool, + apr_hash_t *hash) +{ + return svn_error_trace(svn_ra_local_init(abi_version, pool, hash)); +} + +svn_error_t * +svn_ra_svn__deprecated_init(int abi_version, + apr_pool_t *pool, + apr_hash_t *hash) +{ + return svn_error_trace(svn_ra_svn_init(abi_version, pool, hash)); +} + +svn_error_t * +svn_ra_serf__deprecated_init(int abi_version, + apr_pool_t *pool, + apr_hash_t *hash) +{ + return svn_error_trace(svn_ra_serf_init(abi_version, pool, hash)); +} diff --git a/subversion/libsvn_ra/deprecated.h b/subversion/libsvn_ra/deprecated.h new file mode 100644 index 0000000..205de16 --- /dev/null +++ b/subversion/libsvn_ra/deprecated.h @@ -0,0 +1,60 @@ +/** + * @copyright + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * @endcopyright + */ + + + +#ifndef DEPRECATED_H +#define DEPRECATED_H + +#include <apr_hash.h> + +#include "private/svn_editor.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Non-deprecated wrapper around svn_ra_local_init. */ +svn_error_t * +svn_ra_local__deprecated_init(int abi_version, + apr_pool_t *pool, + apr_hash_t *hash); + +/* Non-deprecated wrapper around svn_ra_svn_init. */ +svn_error_t * +svn_ra_svn__deprecated_init(int abi_version, + apr_pool_t *pool, + apr_hash_t *hash); + +/* Non-deprecated wrapper around svn_ra_serf_init. */ +svn_error_t * +svn_ra_serf__deprecated_init(int abi_version, + apr_pool_t *pool, + apr_hash_t *hash); + +#ifdef __cplusplus +} +#endif + +#endif /* DEPRECATED_H */ diff --git a/subversion/libsvn_ra/editor.c b/subversion/libsvn_ra/editor.c new file mode 100644 index 0000000..ac969ca --- /dev/null +++ b/subversion/libsvn_ra/editor.c @@ -0,0 +1,339 @@ +/* + * editor.c: compatibility editors + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ + +#include <apr_pools.h> + +#include "svn_error.h" +#include "svn_pools.h" +#include "svn_ra.h" +#include "svn_delta.h" +#include "svn_dirent_uri.h" + +#include "private/svn_ra_private.h" +#include "private/svn_delta_private.h" +#include "private/svn_editor.h" + +#include "ra_loader.h" +#include "svn_private_config.h" + + +struct fp_baton { + svn_ra__provide_props_cb_t provide_props_cb; + void *cb_baton; +}; + +struct fb_baton { + svn_ra__provide_base_cb_t provide_base_cb; + void *cb_baton; +}; + +/* The shims currently want a callback that provides props for a given + REPOS_RELPATH at a given BASE_REVISION. However, the RA Ev2 interface + has a callback that provides properties for the REPOS_RELPATH from any + revision, which is returned along with the properties. + + This is a little shim to map between the prototypes. The base revision + for the properties is discarded, and the requested revision (from the + shim code) is ignored. + + The shim code needs to be updated to allow for an RA-style callback + to fetch properties. */ +static svn_error_t * +fetch_props(apr_hash_t **props, + void *baton, + const char *repos_relpath, + svn_revnum_t base_revision, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + struct fp_baton *fpb = baton; + svn_revnum_t unused_revision; + + /* Ignored: BASE_REVISION. */ + + return svn_error_trace(fpb->provide_props_cb(props, &unused_revision, + fpb->cb_baton, + repos_relpath, + result_pool, scratch_pool)); +} + +/* See note above regarding BASE_REVISION. + This also pulls down the entire contents of the file stream from the + RA layer and stores them in a local file, returning the path. +*/ +static svn_error_t * +fetch_base(const char **filename, + void *baton, + const char *repos_relpath, + svn_revnum_t base_revision, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + struct fb_baton *fbb = baton; + svn_revnum_t unused_revision; + svn_stream_t *contents; + svn_stream_t *file_stream; + const char *tmp_filename; + + /* Ignored: BASE_REVISION. */ + + SVN_ERR(fbb->provide_base_cb(&contents, &unused_revision, fbb->cb_baton, + repos_relpath, result_pool, scratch_pool)); + + SVN_ERR(svn_stream_open_unique(&file_stream, &tmp_filename, NULL, + svn_io_file_del_on_pool_cleanup, + scratch_pool, scratch_pool)); + SVN_ERR(svn_stream_copy3(contents, file_stream, NULL, NULL, scratch_pool)); + + *filename = apr_pstrdup(result_pool, tmp_filename); + + + + return SVN_NO_ERROR; +} + + + +svn_error_t * +svn_ra__use_commit_shim(svn_editor_t **editor, + svn_ra_session_t *session, + apr_hash_t *revprop_table, + svn_commit_callback2_t commit_callback, + void *commit_baton, + apr_hash_t *lock_tokens, + svn_boolean_t keep_locks, + svn_ra__provide_base_cb_t provide_base_cb, + svn_ra__provide_props_cb_t provide_props_cb, + svn_ra__get_copysrc_kind_cb_t get_copysrc_kind_cb, + void *cb_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + const svn_delta_editor_t *deditor; + void *dedit_baton; + struct svn_delta__extra_baton *exb; + svn_delta__unlock_func_t unlock_func; + void *unlock_baton; + const char *repos_root; + const char *session_url; + const char *base_relpath; + svn_boolean_t *found_abs_paths; + struct fp_baton *fpb; + + /* NOTE: PROVIDE_BASE_CB is currently unused by this shim. In the future, + we can pass it to the underlying Ev2/Ev1 shim to produce better + apply_txdelta drives (ie. against a base rather than <empty>). */ + + /* Fetch the RA provider's Ev1 commit editor. */ + SVN_ERR(session->vtable->get_commit_editor(session, &deditor, &dedit_baton, + revprop_table, + commit_callback, commit_baton, + lock_tokens, keep_locks, + result_pool)); + + /* Get or calculate the appropriate repos root and base relpath. */ + SVN_ERR(svn_ra_get_repos_root2(session, &repos_root, scratch_pool)); + SVN_ERR(svn_ra_get_session_url(session, &session_url, scratch_pool)); + base_relpath = svn_uri_skip_ancestor(repos_root, session_url, scratch_pool); + + /* We will assume that when the underlying Ev1 editor is finally driven + by the shim, that we will not need to prepend "/" to the paths. Place + this on the heap because it is examined much later. Set to FALSE. */ + found_abs_paths = apr_pcalloc(result_pool, sizeof(*found_abs_paths)); + + /* The PROVIDE_PROPS_CB callback does not match what the shims want. + Let's jigger things around a little bit here. */ + fpb = apr_palloc(result_pool, sizeof(*fpb)); + fpb->provide_props_cb = provide_props_cb; + fpb->cb_baton = cb_baton; + + /* Create the Ev2 editor from the Ev1 editor provided by the RA layer. + + Note: GET_COPYSRC_KIND_CB is compatible in type/semantics with the + shim's FETCH_KIND_FUNC parameter. */ + SVN_ERR(svn_delta__editor_from_delta(editor, &exb, + &unlock_func, &unlock_baton, + deditor, dedit_baton, + found_abs_paths, + repos_root, base_relpath, + cancel_func, cancel_baton, + get_copysrc_kind_cb, cb_baton, + fetch_props, fpb, + result_pool, scratch_pool)); + + /* Note: UNLOCK_FUNC and UNLOCK_BATON are unused during commit drives. + We can safely drop them on the floor. */ + + /* Since we're (currently) just wrapping an existing Ev1 editor, we have + to call any start_edit handler it may provide (the shim uses this to + invoke Ev1's open_root callback). We've got a couple of options to do + so: Implement a wrapper editor and call the start_edit callback upon + the first invocation of any of the underlying editor's functions; or, + just assume our consumer is going to eventually use the editor it is + asking for, and call the start edit callback now. For simplicity's + sake, we do the latter. */ + if (exb->start_edit) + { + /* Most commit drives pass SVN_INVALID_REVNUM for the revision. + All calls to svn_delta_path_driver() pass SVN_INVALID_REVNUM, + so this is fine for any commits done via that function. + + Notably, the PROPSET command passes a specific revision. Before + PROPSET can use the RA Ev2 interface, we may need to make this + revision a parameter. + ### what are the exact semantics? what is the meaning of the + ### revision passed to the Ev1->open_root() callback? */ + SVN_ERR(exb->start_edit(exb->baton, SVN_INVALID_REVNUM)); + } + + /* Note: EXB also contains a TARGET_REVISION function, but that is not + used during commit operations. We can safely ignore it. (ie. it is + in EXB for use by paired-shims) */ + + return SVN_NO_ERROR; +} + + +struct wrapped_replay_baton_t { + svn_ra__replay_revstart_ev2_callback_t revstart_func; + svn_ra__replay_revfinish_ev2_callback_t revfinish_func; + void *replay_baton; + + svn_ra_session_t *session; + + svn_ra__provide_base_cb_t provide_base_cb; + svn_ra__provide_props_cb_t provide_props_cb; + void *cb_baton; + + /* This will be populated by the revstart wrapper. */ + svn_editor_t *editor; +}; + +static svn_error_t * +revstart_func_wrapper(svn_revnum_t revision, + void *replay_baton, + const svn_delta_editor_t **deditor, + void **dedit_baton, + apr_hash_t *rev_props, + apr_pool_t *result_pool) +{ + struct wrapped_replay_baton_t *wrb = replay_baton; + const char *repos_root; + const char *session_url; + const char *base_relpath; + svn_boolean_t *found_abs_paths; + struct fp_baton *fpb; + struct svn_delta__extra_baton *exb; + + /* Get the Ev2 editor from the original revstart func. */ + SVN_ERR(wrb->revstart_func(revision, wrb->replay_baton, &wrb->editor, + rev_props, result_pool)); + + /* Get or calculate the appropriate repos root and base relpath. */ + SVN_ERR(svn_ra_get_repos_root2(wrb->session, &repos_root, result_pool)); + SVN_ERR(svn_ra_get_session_url(wrb->session, &session_url, result_pool)); + base_relpath = svn_uri_skip_ancestor(repos_root, session_url, result_pool); + + /* We will assume that when the underlying Ev1 editor is finally driven + by the shim, that we will not need to prepend "/" to the paths. Place + this on the heap because it is examined much later. Set to FALSE. */ + found_abs_paths = apr_pcalloc(result_pool, sizeof(*found_abs_paths)); + + /* The PROVIDE_PROPS_CB callback does not match what the shims want. + Let's jigger things around a little bit here. */ + fpb = apr_palloc(result_pool, sizeof(*fpb)); + fpb->provide_props_cb = wrb->provide_props_cb; + fpb->cb_baton = wrb->cb_baton; + + /* Create the extra baton. */ + exb = apr_pcalloc(result_pool, sizeof(*exb)); + + /* Create the Ev1 editor from the Ev2 editor provided by the RA layer. + + Note: GET_COPYSRC_KIND_CB is compatible in type/semantics with the + shim's FETCH_KIND_FUNC parameter. */ + SVN_ERR(svn_delta__delta_from_editor(deditor, dedit_baton, wrb->editor, + NULL, NULL, + found_abs_paths, + repos_root, base_relpath, + fetch_props, wrb->cb_baton, + fetch_base, wrb->cb_baton, + exb, result_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +revfinish_func_wrapper(svn_revnum_t revision, + void *replay_baton, + const svn_delta_editor_t *editor, + void *edit_baton, + apr_hash_t *rev_props, + apr_pool_t *pool) +{ + struct wrapped_replay_baton_t *wrb = replay_baton; + + SVN_ERR(wrb->revfinish_func(revision, replay_baton, wrb->editor, rev_props, + pool)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra__use_replay_range_shim(svn_ra_session_t *session, + svn_revnum_t start_revision, + svn_revnum_t end_revision, + svn_revnum_t low_water_mark, + svn_boolean_t send_deltas, + svn_ra__replay_revstart_ev2_callback_t revstart_func, + svn_ra__replay_revfinish_ev2_callback_t revfinish_func, + void *replay_baton, + svn_ra__provide_base_cb_t provide_base_cb, + svn_ra__provide_props_cb_t provide_props_cb, + void *cb_baton, + apr_pool_t *scratch_pool) +{ + /* The basic strategy here is to wrap the callback start and finish + functions to appropriately return an Ev1 editor which is itself wrapped + from the Ev2 one the provided callbacks will give us. */ + + struct wrapped_replay_baton_t *wrb = apr_pcalloc(scratch_pool, sizeof(*wrb)); + + wrb->revstart_func = revstart_func; + wrb->revfinish_func = revfinish_func; + wrb->replay_baton = replay_baton; + wrb->session = session; + + wrb->provide_base_cb = provide_base_cb; + wrb->provide_props_cb = provide_props_cb; + wrb->cb_baton = cb_baton; + + return svn_error_trace(svn_ra_replay_range(session, start_revision, + end_revision, low_water_mark, + send_deltas, + revstart_func_wrapper, + revfinish_func_wrapper, + wrb, scratch_pool)); +} diff --git a/subversion/libsvn_ra/ra_loader.c b/subversion/libsvn_ra/ra_loader.c index b796a80..d9cb96b 100644 --- a/subversion/libsvn_ra/ra_loader.c +++ b/subversion/libsvn_ra/ra_loader.c @@ -33,6 +33,7 @@ #include <apr_hash.h> #include <apr_uri.h> +#include "svn_hash.h" #include "svn_version.h" #include "svn_types.h" #include "svn_error.h" @@ -43,27 +44,17 @@ #include "svn_xml.h" #include "svn_path.h" #include "svn_dso.h" +#include "svn_props.h" +#include "svn_sorts.h" + #include "svn_config.h" #include "ra_loader.h" +#include "deprecated.h" #include "private/svn_ra_private.h" #include "svn_private_config.h" -/* ### This file maps URL schemes to particular RA libraries. - ### Currently, the only pair of RA libraries which support the same - ### protocols are neon and serf. svn_ra_open3 makes the assumption - ### that this is the case; that their 'schemes' fields are both - ### dav_schemes; and that "neon" is listed first. - - ### Users can choose which dav library to use with the http-library - ### preference in .subversion/servers; however, it is ignored by - ### any code which uses the pre-1.2 API svn_ra_get_ra_library - ### instead of svn_ra_open. */ - -#if defined(SVN_HAVE_NEON) && defined(SVN_HAVE_SERF) -#define CHOOSABLE_DAV_MODULE -#endif /* These are the URI schemes that the respective libraries *may* support. @@ -85,20 +76,11 @@ static const struct ra_lib_defn { svn_ra_init_func_t compat_initfunc; } ra_libraries[] = { { - "neon", - dav_schemes, -#ifdef SVN_LIBSVN_CLIENT_LINKS_RA_NEON - svn_ra_neon__init, - svn_ra_dav_init -#endif - }, - - { "svn", svn_schemes, #ifdef SVN_LIBSVN_CLIENT_LINKS_RA_SVN svn_ra_svn__init, - svn_ra_svn_init + svn_ra_svn__deprecated_init #endif }, @@ -107,7 +89,7 @@ static const struct ra_lib_defn { local_schemes, #ifdef SVN_LIBSVN_CLIENT_LINKS_RA_LOCAL svn_ra_local__init, - svn_ra_local_init + svn_ra_local__deprecated_init #endif }, @@ -116,7 +98,7 @@ static const struct ra_lib_defn { dav_schemes, #ifdef SVN_LIBSVN_CLIENT_LINKS_RA_SERF svn_ra_serf__init, - svn_ra_serf_init + svn_ra_serf__deprecated_init #endif }, @@ -159,8 +141,8 @@ load_ra_module(svn_ra__init_func_t *func, const char *compat_funcname; apr_status_t status; - libname = apr_psprintf(pool, "libsvn_ra_%s-%d.so.0", - ra_name, SVN_VER_MAJOR); + libname = apr_psprintf(pool, "libsvn_ra_%s-%d.so.%d", + ra_name, SVN_VER_MAJOR, SVN_SOVERSION); funcname = apr_psprintf(pool, "svn_ra_%s__init", ra_name); compat_funcname = apr_psprintf(pool, "svn_ra_%s_init", ra_name); @@ -201,14 +183,13 @@ load_ra_module(svn_ra__init_func_t *func, return SVN_NO_ERROR; } -/* If DEFN may support URL, return the scheme. Else, return NULL. */ +/* If SCHEMES contains URL, return the scheme. Else, return NULL. */ static const char * -has_scheme_of(const struct ra_lib_defn *defn, const char *url) +has_scheme_of(const char * const *schemes, const char *url) { - const char * const *schemes; apr_size_t len; - for (schemes = defn->schemes; *schemes != NULL; ++schemes) + for ( ; *schemes != NULL; ++schemes) { const char *scheme = *schemes; len = strlen(scheme); @@ -339,8 +320,7 @@ svn_error_t *svn_ra_open4(svn_ra_session_t **session_p, if (config) { /* Grab the 'servers' config. */ - servers = apr_hash_get(config, SVN_CONFIG_CATEGORY_SERVERS, - APR_HASH_KEY_STRING); + servers = svn_hash_gets(config, SVN_CONFIG_CATEGORY_SERVERS); if (servers) { /* First, look in the global section. */ @@ -414,8 +394,7 @@ svn_error_t *svn_ra_open4(svn_ra_session_t **session_p, SVN_CONFIG_OPTION_HTTP_LIBRARY, DEFAULT_HTTP_LIBRARY); - if (strcmp(http_library, "neon") != 0 && - strcmp(http_library, "serf") != 0) + if (strcmp(http_library, "serf") != 0) return svn_error_createf(SVN_ERR_BAD_CONFIG_VALUE, NULL, _("Invalid config: unknown HTTP library " "'%s'"), @@ -454,7 +433,7 @@ svn_error_t *svn_ra_open4(svn_ra_session_t **session_p, { const char *scheme; - if ((scheme = has_scheme_of(defn, repos_URL))) + if ((scheme = has_scheme_of(defn->schemes, repos_URL))) { svn_ra__init_func_t initfunc = defn->initfunc; @@ -475,6 +454,11 @@ svn_error_t *svn_ra_open4(svn_ra_session_t **session_p, SVN_ERR(check_ra_version(vtable->get_version(), scheme)); + if (! has_scheme_of(vtable->get_schemes(sesspool), repos_URL)) + /* Library doesn't support the scheme at runtime. */ + continue; + + break; } } @@ -486,6 +470,8 @@ svn_error_t *svn_ra_open4(svn_ra_session_t **session_p, /* Create the session object. */ session = apr_pcalloc(sesspool, sizeof(*session)); + session->cancel_func = callbacks->cancel_func; + session->cancel_baton = callback_baton; session->vtable = vtable; session->pool = sesspool; @@ -570,19 +556,13 @@ svn_error_t *svn_ra_get_path_relative_to_session(svn_ra_session_t *session, apr_pool_t *pool) { const char *sess_url; + SVN_ERR(session->vtable->get_session_url(session, &sess_url, pool)); - if (strcmp(sess_url, url) == 0) - { - *rel_path = ""; - } - else - { - *rel_path = svn_uri__is_child(sess_url, url, pool); - if (! *rel_path) - return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL, - _("'%s' isn't a child of session URL '%s'"), - url, sess_url); - } + *rel_path = svn_uri_skip_ancestor(sess_url, url, pool); + if (! *rel_path) + return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL, + _("'%s' isn't a child of session URL '%s'"), + url, sess_url); return SVN_NO_ERROR; } @@ -592,21 +572,14 @@ svn_error_t *svn_ra_get_path_relative_to_root(svn_ra_session_t *session, apr_pool_t *pool) { const char *root_url; - SVN_ERR(session->vtable->get_repos_root(session, &root_url, pool)); - if (strcmp(root_url, url) == 0) - { - *rel_path = ""; - } - else - { - *rel_path = svn_uri__is_child(root_url, url, pool); - if (! *rel_path) - return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL, - _("'%s' isn't a child of repository root " - "URL '%s'"), - url, root_url); - } + SVN_ERR(session->vtable->get_repos_root(session, &root_url, pool)); + *rel_path = svn_uri_skip_ancestor(root_url, url, pool); + if (! *rel_path) + return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL, + _("'%s' isn't a child of repository root " + "URL '%s'"), + url, root_url); return SVN_NO_ERROR; } @@ -699,30 +672,56 @@ commit_callback_wrapper(const svn_commit_info_t *commit_info, return ccwb->original_callback(ci, ccwb->original_baton, pool); } + +/* Some RA layers do not correctly fill in REPOS_ROOT in commit_info, or + they are third-party layers conforming to an older commit_info structure. + Interpose a utility function to ensure the field is valid. */ +static void +remap_commit_callback(svn_commit_callback2_t *callback, + void **callback_baton, + svn_ra_session_t *session, + svn_commit_callback2_t original_callback, + void *original_baton, + apr_pool_t *result_pool) +{ + if (original_callback == NULL) + { + *callback = NULL; + *callback_baton = NULL; + } + else + { + /* Allocate this in RESULT_POOL, since the callback will be called + long after this function has returned. */ + struct ccw_baton *ccwb = apr_palloc(result_pool, sizeof(*ccwb)); + + ccwb->session = session; + ccwb->original_callback = original_callback; + ccwb->original_baton = original_baton; + + *callback = commit_callback_wrapper; + *callback_baton = ccwb; + } +} + + svn_error_t *svn_ra_get_commit_editor3(svn_ra_session_t *session, const svn_delta_editor_t **editor, void **edit_baton, apr_hash_t *revprop_table, - svn_commit_callback2_t callback, - void *callback_baton, + svn_commit_callback2_t commit_callback, + void *commit_baton, apr_hash_t *lock_tokens, svn_boolean_t keep_locks, apr_pool_t *pool) { - /* Allocate this in a pool, since the callback will be called long after - this function as returned. */ - struct ccw_baton *ccwb = apr_palloc(pool, sizeof(*ccwb)); - - ccwb->original_callback = callback; - ccwb->original_baton = callback_baton; - ccwb->session = session; + remap_commit_callback(&commit_callback, &commit_baton, + session, commit_callback, commit_baton, + pool); return session->vtable->get_commit_editor(session, editor, edit_baton, revprop_table, - callback - ? commit_callback_wrapper - : NULL, - callback ? ccwb : NULL, + commit_callback, commit_baton, lock_tokens, keep_locks, pool); } @@ -734,24 +733,11 @@ svn_error_t *svn_ra_get_file(svn_ra_session_t *session, apr_hash_t **props, apr_pool_t *pool) { - SVN_ERR_ASSERT(*path != '/'); + SVN_ERR_ASSERT(svn_relpath_is_canonical(path)); return session->vtable->get_file(session, path, revision, stream, fetched_rev, props, pool); } -svn_error_t *svn_ra_get_dir(svn_ra_session_t *session, - const char *path, - svn_revnum_t revision, - apr_hash_t **dirents, - svn_revnum_t *fetched_rev, - apr_hash_t **props, - apr_pool_t *pool) -{ - SVN_ERR_ASSERT(*path != '/'); - return session->vtable->get_dir(session, dirents, fetched_rev, props, - path, revision, SVN_DIRENT_ALL, pool); -} - svn_error_t *svn_ra_get_dir2(svn_ra_session_t *session, apr_hash_t **dirents, svn_revnum_t *fetched_rev, @@ -761,7 +747,7 @@ svn_error_t *svn_ra_get_dir2(svn_ra_session_t *session, apr_uint32_t dirent_fields, apr_pool_t *pool) { - SVN_ERR_ASSERT(*path != '/'); + SVN_ERR_ASSERT(svn_relpath_is_canonical(path)); return session->vtable->get_dir(session, dirents, fetched_rev, props, path, revision, dirent_fields, pool); } @@ -781,7 +767,7 @@ svn_error_t *svn_ra_get_mergeinfo(svn_ra_session_t *session, for (i = 0; i < paths->nelts; i++) { const char *path = APR_ARRAY_IDX(paths, i, const char *); - SVN_ERR_ASSERT(*path != '/'); + SVN_ERR_ASSERT(svn_relpath_is_canonical(path)); } /* Check server Merge Tracking capability. */ @@ -797,16 +783,19 @@ svn_error_t *svn_ra_get_mergeinfo(svn_ra_session_t *session, include_descendants, pool); } -svn_error_t *svn_ra_do_update2(svn_ra_session_t *session, - const svn_ra_reporter3_t **reporter, - void **report_baton, - svn_revnum_t revision_to_update_to, - const char *update_target, - svn_depth_t depth, - svn_boolean_t send_copyfrom_args, - const svn_delta_editor_t *update_editor, - void *update_baton, - apr_pool_t *pool) +svn_error_t * +svn_ra_do_update3(svn_ra_session_t *session, + const svn_ra_reporter3_t **reporter, + void **report_baton, + svn_revnum_t revision_to_update_to, + const char *update_target, + svn_depth_t depth, + svn_boolean_t send_copyfrom_args, + svn_boolean_t ignore_ancestry, + const svn_delta_editor_t *update_editor, + void *update_baton, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { SVN_ERR_ASSERT(svn_path_is_empty(update_target) || svn_path_is_single_path_component(update_target)); @@ -814,28 +803,37 @@ svn_error_t *svn_ra_do_update2(svn_ra_session_t *session, reporter, report_baton, revision_to_update_to, update_target, depth, send_copyfrom_args, + ignore_ancestry, update_editor, update_baton, - pool); + result_pool, scratch_pool); } -svn_error_t *svn_ra_do_switch2(svn_ra_session_t *session, - const svn_ra_reporter3_t **reporter, - void **report_baton, - svn_revnum_t revision_to_switch_to, - const char *switch_target, - svn_depth_t depth, - const char *switch_url, - const svn_delta_editor_t *switch_editor, - void *switch_baton, - apr_pool_t *pool) +svn_error_t * +svn_ra_do_switch3(svn_ra_session_t *session, + const svn_ra_reporter3_t **reporter, + void **report_baton, + svn_revnum_t revision_to_switch_to, + const char *switch_target, + svn_depth_t depth, + const char *switch_url, + svn_boolean_t send_copyfrom_args, + svn_boolean_t ignore_ancestry, + const svn_delta_editor_t *switch_editor, + void *switch_baton, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { SVN_ERR_ASSERT(svn_path_is_empty(switch_target) || svn_path_is_single_path_component(switch_target)); return session->vtable->do_switch(session, reporter, report_baton, revision_to_switch_to, switch_target, - depth, switch_url, switch_editor, - switch_baton, pool); + depth, switch_url, + send_copyfrom_args, + ignore_ancestry, + switch_editor, + switch_baton, + result_pool, scratch_pool); } svn_error_t *svn_ra_do_status2(svn_ra_session_t *session, @@ -869,6 +867,8 @@ svn_error_t *svn_ra_do_diff3(svn_ra_session_t *session, void *diff_baton, apr_pool_t *pool) { + SVN_ERR_ASSERT(svn_path_is_empty(diff_target) + || svn_path_is_single_path_component(diff_target)); return session->vtable->do_diff(session, reporter, report_baton, revision, diff_target, @@ -896,7 +896,7 @@ svn_error_t *svn_ra_get_log2(svn_ra_session_t *session, for (i = 0; i < paths->nelts; i++) { const char *path = APR_ARRAY_IDX(paths, i, const char *); - SVN_ERR_ASSERT(*path != '/'); + SVN_ERR_ASSERT(svn_relpath_is_canonical(path)); } } @@ -915,7 +915,7 @@ svn_error_t *svn_ra_check_path(svn_ra_session_t *session, svn_node_kind_t *kind, apr_pool_t *pool) { - SVN_ERR_ASSERT(*path != '/'); + SVN_ERR_ASSERT(svn_relpath_is_canonical(path)); return session->vtable->check_path(session, path, revision, kind, pool); } @@ -925,7 +925,7 @@ svn_error_t *svn_ra_stat(svn_ra_session_t *session, svn_dirent_t **dirent, apr_pool_t *pool) { - SVN_ERR_ASSERT(*path != '/'); + SVN_ERR_ASSERT(svn_relpath_is_canonical(path)); return session->vtable->stat(session, path, revision, dirent, pool); } @@ -970,7 +970,7 @@ svn_error_t *svn_ra_get_locations(svn_ra_session_t *session, { svn_error_t *err; - SVN_ERR_ASSERT(*path != '/'); + SVN_ERR_ASSERT(svn_relpath_is_canonical(path)); err = session->vtable->get_locations(session, locations, path, peg_revision, location_revisions, pool); if (err && (err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED)) @@ -997,7 +997,7 @@ svn_ra_get_location_segments(svn_ra_session_t *session, { svn_error_t *err; - SVN_ERR_ASSERT(*path != '/'); + SVN_ERR_ASSERT(svn_relpath_is_canonical(path)); err = session->vtable->get_location_segments(session, path, peg_revision, start_rev, end_rev, receiver, receiver_baton, pool); @@ -1025,11 +1025,18 @@ svn_error_t *svn_ra_get_file_revs2(svn_ra_session_t *session, { svn_error_t *err; - SVN_ERR_ASSERT(*path != '/'); + SVN_ERR_ASSERT(svn_relpath_is_canonical(path)); if (include_merged_revisions) SVN_ERR(svn_ra__assert_mergeinfo_capable_server(session, NULL, pool)); + if (start > end) + SVN_ERR( + svn_ra__assert_capable_server(session, + SVN_RA_CAPABILITY_GET_FILE_REVS_REVERSE, + NULL, + pool)); + err = session->vtable->get_file_revs(session, path, start, end, include_merged_revisions, handler, handler_baton, pool); @@ -1058,7 +1065,7 @@ svn_error_t *svn_ra_lock(svn_ra_session_t *session, { const char *path = svn__apr_hash_index_key(hi); - SVN_ERR_ASSERT(*path != '/'); + SVN_ERR_ASSERT(svn_relpath_is_canonical(path)); } if (comment && ! svn_xml_is_xml_safe(comment, strlen(comment))) @@ -1083,7 +1090,7 @@ svn_error_t *svn_ra_unlock(svn_ra_session_t *session, { const char *path = svn__apr_hash_index_key(hi); - SVN_ERR_ASSERT(*path != '/'); + SVN_ERR_ASSERT(svn_relpath_is_canonical(path)); } return session->vtable->unlock(session, path_tokens, break_lock, @@ -1095,7 +1102,7 @@ svn_error_t *svn_ra_get_lock(svn_ra_session_t *session, const char *path, apr_pool_t *pool) { - SVN_ERR_ASSERT(*path != '/'); + SVN_ERR_ASSERT(svn_relpath_is_canonical(path)); return session->vtable->get_lock(session, lock, path, pool); } @@ -1105,7 +1112,7 @@ svn_error_t *svn_ra_get_locks2(svn_ra_session_t *session, svn_depth_t depth, apr_pool_t *pool) { - SVN_ERR_ASSERT(*path != '/'); + SVN_ERR_ASSERT(svn_relpath_is_canonical(path)); SVN_ERR_ASSERT((depth == svn_depth_empty) || (depth == svn_depth_files) || (depth == svn_depth_immediates) || @@ -1134,6 +1141,58 @@ svn_error_t *svn_ra_replay(svn_ra_session_t *session, } svn_error_t * +svn_ra__replay_ev2(svn_ra_session_t *session, + svn_revnum_t revision, + svn_revnum_t low_water_mark, + svn_boolean_t send_deltas, + svn_editor_t *editor, + apr_pool_t *scratch_pool) +{ + SVN__NOT_IMPLEMENTED(); +} + +static svn_error_t * +replay_range_from_replays(svn_ra_session_t *session, + svn_revnum_t start_revision, + svn_revnum_t end_revision, + svn_revnum_t low_water_mark, + svn_boolean_t text_deltas, + svn_ra_replay_revstart_callback_t revstart_func, + svn_ra_replay_revfinish_callback_t revfinish_func, + void *replay_baton, + apr_pool_t *scratch_pool) +{ + apr_pool_t *iterpool = svn_pool_create(scratch_pool); + svn_revnum_t rev; + + for (rev = start_revision ; rev <= end_revision ; rev++) + { + const svn_delta_editor_t *editor; + void *edit_baton; + apr_hash_t *rev_props; + + svn_pool_clear(iterpool); + + SVN_ERR(svn_ra_rev_proplist(session, rev, &rev_props, iterpool)); + + SVN_ERR(revstart_func(rev, replay_baton, + &editor, &edit_baton, + rev_props, + iterpool)); + SVN_ERR(svn_ra_replay(session, rev, low_water_mark, + text_deltas, editor, edit_baton, + iterpool)); + SVN_ERR(revfinish_func(rev, replay_baton, + editor, edit_baton, + rev_props, + iterpool)); + } + svn_pool_destroy(iterpool); + + return SVN_NO_ERROR; +} + +svn_error_t * svn_ra_replay_range(svn_ra_session_t *session, svn_revnum_t start_revision, svn_revnum_t end_revision, @@ -1150,40 +1209,60 @@ svn_ra_replay_range(svn_ra_session_t *session, revstart_func, revfinish_func, replay_baton, pool); - if (err && (err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED)) - { - apr_pool_t *subpool = svn_pool_create(pool); - svn_revnum_t rev; - - svn_error_clear(err); - err = SVN_NO_ERROR; + if (!err || (err && (err->apr_err != SVN_ERR_RA_NOT_IMPLEMENTED))) + return svn_error_trace(err); + + svn_error_clear(err); + return svn_error_trace(replay_range_from_replays(session, start_revision, + end_revision, + low_water_mark, + text_deltas, + revstart_func, + revfinish_func, + replay_baton, pool)); +} - for (rev = start_revision ; rev <= end_revision ; rev++) - { - const svn_delta_editor_t *editor; - void *edit_baton; - apr_hash_t *rev_props; - - svn_pool_clear(subpool); - - SVN_ERR(svn_ra_rev_proplist(session, rev, &rev_props, subpool)); - - SVN_ERR(revstart_func(rev, replay_baton, - &editor, &edit_baton, - rev_props, - subpool)); - SVN_ERR(svn_ra_replay(session, rev, low_water_mark, - text_deltas, editor, edit_baton, - subpool)); - SVN_ERR(revfinish_func(rev, replay_baton, - editor, edit_baton, - rev_props, - subpool)); - } - svn_pool_destroy(subpool); +svn_error_t * +svn_ra__replay_range_ev2(svn_ra_session_t *session, + svn_revnum_t start_revision, + svn_revnum_t end_revision, + svn_revnum_t low_water_mark, + svn_boolean_t send_deltas, + svn_ra__replay_revstart_ev2_callback_t revstart_func, + svn_ra__replay_revfinish_ev2_callback_t revfinish_func, + void *replay_baton, + svn_ra__provide_base_cb_t provide_base_cb, + svn_ra__provide_props_cb_t provide_props_cb, + svn_ra__get_copysrc_kind_cb_t get_copysrc_kind_cb, + void *cb_baton, + apr_pool_t *scratch_pool) +{ + if (session->vtable->replay_range_ev2 == NULL) + { + /* The specific RA layer does not have an implementation. Use our + default shim over the normal replay editor. */ + + /* This will call the Ev1 replay range handler with modified + callbacks. */ + return svn_error_trace(svn_ra__use_replay_range_shim( + session, + start_revision, + end_revision, + low_water_mark, + send_deltas, + revstart_func, + revfinish_func, + replay_baton, + provide_base_cb, + provide_props_cb, + cb_baton, + scratch_pool)); } - return err; + return svn_error_trace(session->vtable->replay_range_ev2( + session, start_revision, end_revision, + low_water_mark, send_deltas, revstart_func, + revfinish_func, replay_baton, scratch_pool)); } svn_error_t *svn_ra_has_capability(svn_ra_session_t *session, @@ -1205,7 +1284,7 @@ svn_ra_get_deleted_rev(svn_ra_session_t *session, svn_error_t *err; /* Path must be relative. */ - SVN_ERR_ASSERT(*path != '/'); + SVN_ERR_ASSERT(svn_relpath_is_canonical(path)); if (!SVN_IS_VALID_REVNUM(peg_revision)) return svn_error_createf(SVN_ERR_CLIENT_BAD_REVISION, NULL, @@ -1221,8 +1300,7 @@ svn_ra_get_deleted_rev(svn_ra_session_t *session, end_revision, revision_deleted, pool); - if (err && (err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE /* serf */ - || err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED)) /* neon */ + if (err && (err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE)) { svn_error_clear(err); @@ -1234,6 +1312,96 @@ svn_ra_get_deleted_rev(svn_ra_session_t *session, return err; } +svn_error_t * +svn_ra_get_inherited_props(svn_ra_session_t *session, + apr_array_header_t **iprops, + const char *path, + svn_revnum_t revision, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + svn_boolean_t iprop_capable; + + /* Path must be relative. */ + SVN_ERR_ASSERT(svn_relpath_is_canonical(path)); + + SVN_ERR(svn_ra_has_capability(session, &iprop_capable, + SVN_RA_CAPABILITY_INHERITED_PROPS, + scratch_pool)); + + if (iprop_capable) + { + SVN_ERR(session->vtable->get_inherited_props(session, iprops, path, + revision, result_pool, + scratch_pool)); + } + else + { + /* Fallback for legacy servers. */ + SVN_ERR(svn_ra__get_inherited_props_walk(session, path, revision, iprops, + result_pool, scratch_pool)); + } + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra__get_commit_ev2(svn_editor_t **editor, + svn_ra_session_t *session, + apr_hash_t *revprop_table, + svn_commit_callback2_t commit_callback, + void *commit_baton, + apr_hash_t *lock_tokens, + svn_boolean_t keep_locks, + svn_ra__provide_base_cb_t provide_base_cb, + svn_ra__provide_props_cb_t provide_props_cb, + svn_ra__get_copysrc_kind_cb_t get_copysrc_kind_cb, + void *cb_baton, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + if (session->vtable->get_commit_ev2 == NULL) + { + /* The specific RA layer does not have an implementation. Use our + default shim over the normal commit editor. */ + + /* Remap for RA layers exposing Ev1. */ + remap_commit_callback(&commit_callback, &commit_baton, + session, commit_callback, commit_baton, + result_pool); + + return svn_error_trace(svn_ra__use_commit_shim( + editor, + session, + revprop_table, + commit_callback, commit_baton, + lock_tokens, + keep_locks, + provide_base_cb, + provide_props_cb, + get_copysrc_kind_cb, + cb_baton, + session->cancel_func, session->cancel_baton, + result_pool, scratch_pool)); + } + + /* Note: no need to remap the callback for Ev2. RA layers providing this + vtable entry should completely fill in commit_info. */ + + return svn_error_trace(session->vtable->get_commit_ev2( + editor, + session, + revprop_table, + commit_callback, commit_baton, + lock_tokens, + keep_locks, + provide_base_cb, + provide_props_cb, + get_copysrc_kind_cb, + cb_baton, + session->cancel_func, session->cancel_baton, + result_pool, scratch_pool)); +} svn_error_t * @@ -1268,7 +1436,7 @@ svn_ra_print_modules(svn_stringbuf_t *output, built with SASL. */ line = apr_psprintf(iterpool, "* ra_%s : %s\n", defn->ra_name, - vtable->get_description()); + vtable->get_description(iterpool)); svn_stringbuf_appendcstr(output, line); for (schemes = vtable->get_schemes(iterpool); *schemes != NULL; @@ -1292,11 +1460,20 @@ svn_ra_print_ra_libraries(svn_stringbuf_t **descriptions, void *ra_baton, apr_pool_t *pool) { - *descriptions = svn_stringbuf_create("", pool); + *descriptions = svn_stringbuf_create_empty(pool); return svn_ra_print_modules(*descriptions, pool); } +svn_error_t * +svn_ra__register_editor_shim_callbacks(svn_ra_session_t *session, + svn_delta_shim_callbacks_t *callbacks) +{ + SVN_ERR(session->vtable->register_editor_shim_callbacks(session, callbacks)); + return SVN_NO_ERROR; +} + + /* Return the library version number. */ const svn_version_t * svn_ra_version(void) @@ -1328,7 +1505,7 @@ svn_ra_get_ra_library(svn_ra_plugin_t **library, for (defn = ra_libraries; defn->ra_name != NULL; ++defn) { const char *scheme; - if ((scheme = has_scheme_of(defn, url))) + if ((scheme = has_scheme_of(defn->schemes, url))) { svn_ra_init_func_t compat_initfunc = defn->compat_initfunc; @@ -1344,7 +1521,7 @@ svn_ra_get_ra_library(svn_ra_plugin_t **library, SVN_ERR(compat_initfunc(SVN_RA_ABI_VERSION, load_pool, ht)); - *library = apr_hash_get(ht, scheme, APR_HASH_KEY_STRING); + *library = svn_hash_gets(ht, scheme); /* The library may support just a subset of the schemes listed, so we have to check here too. */ diff --git a/subversion/libsvn_ra/ra_loader.h b/subversion/libsvn_ra/ra_loader.h index ddb2581..227730a 100644 --- a/subversion/libsvn_ra/ra_loader.h +++ b/subversion/libsvn_ra/ra_loader.h @@ -32,6 +32,8 @@ #include "svn_ra.h" +#include "private/svn_ra_private.h" + #ifdef __cplusplus extern "C" { #endif @@ -43,7 +45,7 @@ typedef struct svn_ra__vtable_t { /* Return a short description of the RA implementation, as a localized * string. */ - const char *(*get_description)(void); + const char *(*get_description)(apr_pool_t *pool); /* Return a list of actual URI schemes supported by this implementation. * The returned array is NULL-terminated. */ @@ -56,7 +58,7 @@ typedef struct svn_ra__vtable_t { time this is called. SESSION->priv may be set by this function. */ svn_error_t *(*open_session)(svn_ra_session_t *session, const char **corrected_url, - const char *repos_URL, + const char *session_URL, const svn_ra_callbacks2_t *callbacks, void *callback_baton, apr_hash_t *config, @@ -133,7 +135,7 @@ typedef struct svn_ra__vtable_t { svn_mergeinfo_inheritance_t inherit, svn_boolean_t include_merged_revisions, apr_pool_t *pool); - /* See svn_ra_do_update2(). */ + /* See svn_ra_do_update3(). */ svn_error_t *(*do_update)(svn_ra_session_t *session, const svn_ra_reporter3_t **reporter, void **report_baton, @@ -141,10 +143,12 @@ typedef struct svn_ra__vtable_t { const char *update_target, svn_depth_t depth, svn_boolean_t send_copyfrom_args, + svn_boolean_t ignore_ancestry, const svn_delta_editor_t *update_editor, void *update_baton, - apr_pool_t *pool); - /* See svn_ra_do_switch2(). */ + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + /* See svn_ra_do_switch3(). */ svn_error_t *(*do_switch)(svn_ra_session_t *session, const svn_ra_reporter3_t **reporter, void **report_baton, @@ -152,9 +156,12 @@ typedef struct svn_ra__vtable_t { const char *switch_target, svn_depth_t depth, const char *switch_url, + svn_boolean_t send_copyfrom_args, + svn_boolean_t ignore_ancestry, const svn_delta_editor_t *switch_editor, void *switch_baton, - apr_pool_t *pool); + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); /* See svn_ra_do_status2(). */ svn_error_t *(*do_status)(svn_ra_session_t *session, const svn_ra_reporter3_t **reporter, @@ -294,12 +301,56 @@ typedef struct svn_ra__vtable_t { svn_revnum_t *revision_deleted, apr_pool_t *pool); + /* See svn_ra__register_editor_shim_callbacks() */ + svn_error_t *(*register_editor_shim_callbacks)(svn_ra_session_t *session, + svn_delta_shim_callbacks_t *callbacks); + /* See svn_ra_get_inherited_props(). */ + svn_error_t *(*get_inherited_props)(svn_ra_session_t *session, + apr_array_header_t **iprops, + const char *path, + svn_revnum_t revision, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + /* See svn_ra__get_commit_ev2() */ + svn_error_t *(*get_commit_ev2)( + svn_editor_t **editor, + svn_ra_session_t *session, + apr_hash_t *revprop_table, + svn_commit_callback2_t callback, + void *callback_baton, + apr_hash_t *lock_tokens, + svn_boolean_t keep_locks, + svn_ra__provide_base_cb_t provide_base_cb, + svn_ra__provide_props_cb_t provide_props_cb, + svn_ra__get_copysrc_kind_cb_t get_copysrc_kind_cb, + void *cb_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + + /* See svn_ra__replay_range_ev2() */ + svn_error_t *(*replay_range_ev2)( + svn_ra_session_t *session, + svn_revnum_t start_revision, + svn_revnum_t end_revision, + svn_revnum_t low_water_mark, + svn_boolean_t send_deltas, + svn_ra__replay_revstart_ev2_callback_t revstart_func, + svn_ra__replay_revfinish_ev2_callback_t revfinish_func, + void *replay_baton, + apr_pool_t *scratch_pool); + } svn_ra__vtable_t; /* The RA session object. */ struct svn_ra_session_t { const svn_ra__vtable_t *vtable; + /* Cancellation handlers consumers may want to use. */ + svn_cancel_func_t cancel_func; + void *cancel_baton; + /* Pool used to manage this session. */ apr_pool_t *pool; @@ -329,9 +380,6 @@ svn_error_t *svn_ra_local__init(const svn_version_t *loader_version, svn_error_t *svn_ra_svn__init(const svn_version_t *loader_version, const svn_ra__vtable_t **vtable, apr_pool_t *pool); -svn_error_t *svn_ra_neon__init(const svn_version_t *loader_version, - const svn_ra__vtable_t **vtable, - apr_pool_t *pool); svn_error_t *svn_ra_serf__init(const svn_version_t *loader_version, const svn_ra__vtable_t **vtable, apr_pool_t *pool); @@ -451,6 +499,62 @@ svn_ra__get_deleted_rev_from_log(svn_ra_session_t *session, svn_revnum_t *revision_deleted, apr_pool_t *pool); + +/** + * Fallback logic for svn_ra_get_inherited_props() when that API + * need to find PATH's inherited properties on a legacy server that + * doesn't have the SVN_RA_CAPABILITY_INHERITED_PROPS capability. + * + * All arguments are as per svn_ra_get_inherited_props(). + */ +svn_error_t * +svn_ra__get_inherited_props_walk(svn_ra_session_t *session, + const char *path, + svn_revnum_t revision, + apr_array_header_t **inherited_props, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + +/* Utility function to provide a shim between a returned Ev2 and an RA + provider's Ev1-based commit editor. + + See svn_ra__get_commit_ev2() for parameter semantics. */ +svn_error_t * +svn_ra__use_commit_shim(svn_editor_t **editor, + svn_ra_session_t *session, + apr_hash_t *revprop_table, + svn_commit_callback2_t callback, + void *callback_baton, + apr_hash_t *lock_tokens, + svn_boolean_t keep_locks, + svn_ra__provide_base_cb_t provide_base_cb, + svn_ra__provide_props_cb_t provide_props_cb, + svn_ra__get_copysrc_kind_cb_t get_copysrc_kind_cb, + void *cb_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + +/* Utility function to provide a shim between a returned Ev2 and an RA + provider's Ev1-based commit editor. + + See svn_ra__replay_range_ev2() for parameter semantics. */ +svn_error_t * +svn_ra__use_replay_range_shim(svn_ra_session_t *session, + svn_revnum_t start_revision, + svn_revnum_t end_revision, + svn_revnum_t low_water_mark, + svn_boolean_t send_deltas, + svn_ra__replay_revstart_ev2_callback_t revstart_func, + svn_ra__replay_revfinish_ev2_callback_t revfinish_func, + void *replay_baton, + svn_ra__provide_base_cb_t provide_base_cb, + svn_ra__provide_props_cb_t provide_props_cb, + void *cb_baton, + apr_pool_t *scratch_pool); + + #ifdef __cplusplus } #endif diff --git a/subversion/libsvn_ra/util.c b/subversion/libsvn_ra/util.c index 47e4865..d9a4520 100644 --- a/subversion/libsvn_ra/util.c +++ b/subversion/libsvn_ra/util.c @@ -38,6 +38,26 @@ #include "svn_private_config.h" #include "private/svn_ra_private.h" +static const char * +get_path(const char *path_or_url, + svn_ra_session_t *ra_session, + apr_pool_t *pool) +{ + if (path_or_url == NULL) + { + svn_error_t *err = svn_ra_get_session_url(ra_session, &path_or_url, + pool); + if (err) + { + /* The SVN_ERR_UNSUPPORTED_FEATURE error in the caller is more + important, so dummy up the session's URL and chuck this error. */ + svn_error_clear(err); + return _("<repository>"); + } + } + return path_or_url; +} + svn_error_t * svn_ra__assert_mergeinfo_capable_server(svn_ra_session_t *ra_session, const char *path_or_url, @@ -48,18 +68,7 @@ svn_ra__assert_mergeinfo_capable_server(svn_ra_session_t *ra_session, SVN_RA_CAPABILITY_MERGEINFO, pool)); if (! mergeinfo_capable) { - if (path_or_url == NULL) - { - svn_error_t *err = svn_ra_get_session_url(ra_session, &path_or_url, - pool); - if (err) - { - /* The SVN_ERR_UNSUPPORTED_FEATURE error is more important, - so dummy up the session's URL and chuck this error. */ - svn_error_clear(err); - path_or_url = "<repository>"; - } - } + path_or_url = get_path(path_or_url, ra_session, pool); return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL, _("Retrieval of mergeinfo unsupported by '%s'"), svn_path_is_url(path_or_url) @@ -69,6 +78,35 @@ svn_ra__assert_mergeinfo_capable_server(svn_ra_session_t *ra_session, return SVN_NO_ERROR; } +svn_error_t * +svn_ra__assert_capable_server(svn_ra_session_t *ra_session, + const char *capability, + const char *path_or_url, + apr_pool_t *pool) +{ + if (!strcmp(capability, SVN_RA_CAPABILITY_MERGEINFO)) + return svn_ra__assert_mergeinfo_capable_server(ra_session, path_or_url, + pool); + + else + { + svn_boolean_t has; + SVN_ERR(svn_ra_has_capability(ra_session, &has, capability, pool)); + if (! has) + { + path_or_url = get_path(path_or_url, ra_session, pool); + return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL, + _("The '%s' feature is not supported by '%s'"), + capability, + svn_path_is_url(path_or_url) + ? path_or_url + : svn_dirent_local_style(path_or_url, + pool)); + } + } + return SVN_NO_ERROR; +} + /* Does ERR mean "the current value of the revprop isn't equal to the *OLD_VALUE_P you gave me"? */ diff --git a/subversion/libsvn_ra/wrapper_template.h b/subversion/libsvn_ra/wrapper_template.h index e5426dc..cee3fb3 100644 --- a/subversion/libsvn_ra/wrapper_template.h +++ b/subversion/libsvn_ra/wrapper_template.h @@ -291,8 +291,10 @@ static svn_error_t *compat_do_update(void *session_baton, SVN_ERR(VTBL.do_update(session_baton, &reporter3, &baton3, revision_to_update_to, update_target, depth, - FALSE, /* no copyfrom args */ - editor, update_baton, pool)); + FALSE /* send_copyfrom_args */, + FALSE /* ignore_ancestry */, + editor, update_baton, + pool, pool)); compat_wrap_reporter(reporter, report_baton, reporter3, baton3, pool); return SVN_NO_ERROR; @@ -315,7 +317,11 @@ static svn_error_t *compat_do_switch(void *session_baton, SVN_ERR(VTBL.do_switch(session_baton, &reporter3, &baton3, revision_to_switch_to, switch_target, depth, - switch_url, editor, switch_baton, pool)); + switch_url, + FALSE /* send_copyfrom_args */, + TRUE /* ignore_ancestry */, + editor, switch_baton, + pool /* result_pool */, pool /* scratch_pool */)); compat_wrap_reporter(reporter, report_baton, reporter3, baton3, pool); |
