summaryrefslogtreecommitdiffstats
path: root/subversion/libsvn_ra/ra_loader.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_ra/ra_loader.c')
-rw-r--r--subversion/libsvn_ra/ra_loader.c1576
1 files changed, 1576 insertions, 0 deletions
diff --git a/subversion/libsvn_ra/ra_loader.c b/subversion/libsvn_ra/ra_loader.c
new file mode 100644
index 0000000..4afcb59
--- /dev/null
+++ b/subversion/libsvn_ra/ra_loader.c
@@ -0,0 +1,1576 @@
+/*
+ * ra_loader.c: logic for loading different RA library implementations
+ *
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ */
+
+/* ==================================================================== */
+
+/*** Includes. ***/
+#define APR_WANT_STRFUNC
+#include <apr_want.h>
+
+#include <apr.h>
+#include <apr_strings.h>
+#include <apr_pools.h>
+#include <apr_hash.h>
+#include <apr_uri.h>
+
+#include "svn_hash.h"
+#include "svn_version.h"
+#include "svn_types.h"
+#include "svn_error.h"
+#include "svn_error_codes.h"
+#include "svn_pools.h"
+#include "svn_delta.h"
+#include "svn_ra.h"
+#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"
+
+
+
+
+/* These are the URI schemes that the respective libraries *may* support.
+ * The schemes actually supported may be a subset of the schemes listed below.
+ * This can't be determine until the library is loaded.
+ * (Currently, this applies to the https scheme, which is only
+ * available if SSL is supported.) */
+static const char * const dav_schemes[] = { "http", "https", NULL };
+static const char * const svn_schemes[] = { "svn", NULL };
+static const char * const local_schemes[] = { "file", NULL };
+
+static const struct ra_lib_defn {
+ /* the name of this RA library (e.g. "neon" or "local") */
+ const char *ra_name;
+
+ const char * const *schemes;
+ /* the initialization function if linked in; otherwise, NULL */
+ svn_ra__init_func_t initfunc;
+ svn_ra_init_func_t compat_initfunc;
+} ra_libraries[] = {
+ {
+ "svn",
+ svn_schemes,
+#ifdef SVN_LIBSVN_CLIENT_LINKS_RA_SVN
+ svn_ra_svn__init,
+ svn_ra_svn__deprecated_init
+#endif
+ },
+
+ {
+ "local",
+ local_schemes,
+#ifdef SVN_LIBSVN_CLIENT_LINKS_RA_LOCAL
+ svn_ra_local__init,
+ svn_ra_local__deprecated_init
+#endif
+ },
+
+ {
+ "serf",
+ dav_schemes,
+#ifdef SVN_LIBSVN_CLIENT_LINKS_RA_SERF
+ svn_ra_serf__init,
+ svn_ra_serf__deprecated_init
+#endif
+ },
+
+ /* ADD NEW RA IMPLEMENTATIONS HERE (as they're written) */
+
+ /* sentinel */
+ { NULL }
+};
+
+/* Ensure that the RA library NAME is loaded.
+ *
+ * If FUNC is non-NULL, set *FUNC to the address of the svn_ra_NAME__init
+ * function of the library.
+ *
+ * If COMPAT_FUNC is non-NULL, set *COMPAT_FUNC to the address of the
+ * svn_ra_NAME_init compatibility init function of the library.
+ *
+ * ### todo: Any RA libraries implemented from this point forward
+ * ### don't really need an svn_ra_NAME_init compatibility function.
+ * ### Currently, load_ra_module() will error if no such function is
+ * ### found, but it might be more friendly to simply set *COMPAT_FUNC
+ * ### to null (assuming COMPAT_FUNC itself is non-null).
+ */
+static svn_error_t *
+load_ra_module(svn_ra__init_func_t *func,
+ svn_ra_init_func_t *compat_func,
+ const char *ra_name, apr_pool_t *pool)
+{
+ if (func)
+ *func = NULL;
+ if (compat_func)
+ *compat_func = NULL;
+
+#if defined(SVN_USE_DSO) && APR_HAS_DSO
+ {
+ apr_dso_handle_t *dso;
+ apr_dso_handle_sym_t symbol;
+ const char *libname;
+ const char *funcname;
+ const char *compat_funcname;
+ apr_status_t status;
+
+ 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);
+
+ /* find/load the specified library */
+ SVN_ERR(svn_dso_load(&dso, libname));
+ if (! dso)
+ return SVN_NO_ERROR;
+
+ /* find the initialization routines */
+ if (func)
+ {
+ status = apr_dso_sym(&symbol, dso, funcname);
+ if (status)
+ {
+ return svn_error_wrap_apr(status,
+ _("'%s' does not define '%s()'"),
+ libname, funcname);
+ }
+
+ *func = (svn_ra__init_func_t) symbol;
+ }
+
+ if (compat_func)
+ {
+ status = apr_dso_sym(&symbol, dso, compat_funcname);
+ if (status)
+ {
+ return svn_error_wrap_apr(status,
+ _("'%s' does not define '%s()'"),
+ libname, compat_funcname);
+ }
+
+ *compat_func = (svn_ra_init_func_t) symbol;
+ }
+ }
+#endif /* APR_HAS_DSO */
+
+ return SVN_NO_ERROR;
+}
+
+/* If SCHEMES contains URL, return the scheme. Else, return NULL. */
+static const char *
+has_scheme_of(const char * const *schemes, const char *url)
+{
+ apr_size_t len;
+
+ for ( ; *schemes != NULL; ++schemes)
+ {
+ const char *scheme = *schemes;
+ len = strlen(scheme);
+ /* Case-insensitive comparison, per RFC 2396 section 3.1. Allow
+ URL to contain a trailing "+foo" section in the scheme, since
+ that's how we specify tunnel schemes in ra_svn. */
+ if (strncasecmp(scheme, url, len) == 0 &&
+ (url[len] == ':' || url[len] == '+'))
+ return scheme;
+ }
+
+ return NULL;
+}
+
+/* Return an error if RA_VERSION doesn't match the version of this library.
+ Use SCHEME in the error message to describe the library that was loaded. */
+static svn_error_t *
+check_ra_version(const svn_version_t *ra_version, const char *scheme)
+{
+ const svn_version_t *my_version = svn_ra_version();
+ if (!svn_ver_equal(my_version, ra_version))
+ return svn_error_createf(SVN_ERR_VERSION_MISMATCH, NULL,
+ _("Mismatched RA version for '%s':"
+ " found %d.%d.%d%s,"
+ " expected %d.%d.%d%s"),
+ scheme,
+ my_version->major, my_version->minor,
+ my_version->patch, my_version->tag,
+ ra_version->major, ra_version->minor,
+ ra_version->patch, ra_version->tag);
+
+ return SVN_NO_ERROR;
+}
+
+/* -------------------------------------------------------------- */
+
+/*** Public Interfaces ***/
+
+svn_error_t *svn_ra_initialize(apr_pool_t *pool)
+{
+ return SVN_NO_ERROR;
+}
+
+/* Please note: the implementation of svn_ra_create_callbacks is
+ * duplicated in libsvn_ra/wrapper_template.h:compat_open() . This
+ * duplication is intentional, is there to avoid a circular
+ * dependancy, and is justified in great length in the code of
+ * compat_open() in libsvn_ra/wrapper_template.h. If you modify the
+ * implementation of svn_ra_create_callbacks(), be sure to keep the
+ * code in wrapper_template.h:compat_open() in sync with your
+ * changes. */
+svn_error_t *
+svn_ra_create_callbacks(svn_ra_callbacks2_t **callbacks,
+ apr_pool_t *pool)
+{
+ *callbacks = apr_pcalloc(pool, sizeof(**callbacks));
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *svn_ra_open4(svn_ra_session_t **session_p,
+ const char **corrected_url_p,
+ const char *repos_URL,
+ const char *uuid,
+ const svn_ra_callbacks2_t *callbacks,
+ void *callback_baton,
+ apr_hash_t *config,
+ apr_pool_t *pool)
+{
+ apr_pool_t *sesspool = svn_pool_create(pool);
+ svn_ra_session_t *session;
+ const struct ra_lib_defn *defn;
+ const svn_ra__vtable_t *vtable = NULL;
+ svn_config_t *servers = NULL;
+ const char *server_group;
+ apr_uri_t repos_URI;
+ apr_status_t apr_err;
+#ifdef CHOOSABLE_DAV_MODULE
+ const char *http_library = DEFAULT_HTTP_LIBRARY;
+#endif
+ /* Auth caching parameters. */
+ svn_boolean_t store_passwords = SVN_CONFIG_DEFAULT_OPTION_STORE_PASSWORDS;
+ svn_boolean_t store_auth_creds = SVN_CONFIG_DEFAULT_OPTION_STORE_AUTH_CREDS;
+ const char *store_plaintext_passwords
+ = SVN_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS;
+ svn_boolean_t store_pp = SVN_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP;
+ const char *store_pp_plaintext
+ = SVN_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT;
+ const char *corrected_url;
+
+ /* Initialize the return variable. */
+ *session_p = NULL;
+
+ apr_err = apr_uri_parse(sesspool, repos_URL, &repos_URI);
+ /* ### Should apr_uri_parse leave hostname NULL? It doesn't
+ * for "file:///" URLs, only for bogus URLs like "bogus".
+ * If this is the right behavior for apr_uri_parse, maybe we
+ * should have a svn_uri_parse wrapper. */
+ if (apr_err != APR_SUCCESS || repos_URI.hostname == NULL)
+ return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
+ _("Illegal repository URL '%s'"),
+ repos_URL);
+
+ if (callbacks->auth_baton)
+ {
+ /* The 'store-passwords' and 'store-auth-creds' parameters used to
+ * live in SVN_CONFIG_CATEGORY_CONFIG. For backward compatibility,
+ * if values for these parameters have already been set by our
+ * callers, we use those values as defaults.
+ *
+ * Note that we can only catch the case where users explicitly set
+ * "store-passwords = no" or 'store-auth-creds = no".
+ *
+ * However, since the default value for both these options is
+ * currently (and has always been) "yes", users won't know
+ * the difference if they set "store-passwords = yes" or
+ * "store-auth-creds = yes" -- they'll get the expected behaviour.
+ */
+
+ if (svn_auth_get_parameter(callbacks->auth_baton,
+ SVN_AUTH_PARAM_DONT_STORE_PASSWORDS) != NULL)
+ store_passwords = FALSE;
+
+ if (svn_auth_get_parameter(callbacks->auth_baton,
+ SVN_AUTH_PARAM_NO_AUTH_CACHE) != NULL)
+ store_auth_creds = FALSE;
+ }
+
+ if (config)
+ {
+ /* Grab the 'servers' config. */
+ servers = svn_hash_gets(config, SVN_CONFIG_CATEGORY_SERVERS);
+ if (servers)
+ {
+ /* First, look in the global section. */
+
+ SVN_ERR(svn_config_get_bool
+ (servers, &store_passwords, SVN_CONFIG_SECTION_GLOBAL,
+ SVN_CONFIG_OPTION_STORE_PASSWORDS,
+ store_passwords));
+
+ SVN_ERR(svn_config_get_yes_no_ask
+ (servers, &store_plaintext_passwords, SVN_CONFIG_SECTION_GLOBAL,
+ SVN_CONFIG_OPTION_STORE_PLAINTEXT_PASSWORDS,
+ SVN_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS));
+
+ SVN_ERR(svn_config_get_bool
+ (servers, &store_pp, SVN_CONFIG_SECTION_GLOBAL,
+ SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP,
+ store_pp));
+
+ SVN_ERR(svn_config_get_yes_no_ask
+ (servers, &store_pp_plaintext,
+ SVN_CONFIG_SECTION_GLOBAL,
+ SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
+ SVN_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT));
+
+ SVN_ERR(svn_config_get_bool
+ (servers, &store_auth_creds, SVN_CONFIG_SECTION_GLOBAL,
+ SVN_CONFIG_OPTION_STORE_AUTH_CREDS,
+ store_auth_creds));
+
+ /* Find out where we're about to connect to, and
+ * try to pick a server group based on the destination. */
+ server_group = svn_config_find_group(servers, repos_URI.hostname,
+ SVN_CONFIG_SECTION_GROUPS,
+ sesspool);
+
+ if (server_group)
+ {
+ /* Override global auth caching parameters with the ones
+ * for the server group, if any. */
+ SVN_ERR(svn_config_get_bool(servers, &store_auth_creds,
+ server_group,
+ SVN_CONFIG_OPTION_STORE_AUTH_CREDS,
+ store_auth_creds));
+
+ SVN_ERR(svn_config_get_bool(servers, &store_passwords,
+ server_group,
+ SVN_CONFIG_OPTION_STORE_PASSWORDS,
+ store_passwords));
+
+ SVN_ERR(svn_config_get_yes_no_ask
+ (servers, &store_plaintext_passwords, server_group,
+ SVN_CONFIG_OPTION_STORE_PLAINTEXT_PASSWORDS,
+ store_plaintext_passwords));
+
+ SVN_ERR(svn_config_get_bool
+ (servers, &store_pp,
+ server_group, SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP,
+ store_pp));
+
+ SVN_ERR(svn_config_get_yes_no_ask
+ (servers, &store_pp_plaintext, server_group,
+ SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
+ store_pp_plaintext));
+ }
+#ifdef CHOOSABLE_DAV_MODULE
+ /* Now, which DAV-based RA method do we want to use today? */
+ http_library
+ = svn_config_get_server_setting(servers,
+ server_group, /* NULL is OK */
+ SVN_CONFIG_OPTION_HTTP_LIBRARY,
+ DEFAULT_HTTP_LIBRARY);
+
+ if (strcmp(http_library, "serf") != 0)
+ return svn_error_createf(SVN_ERR_BAD_CONFIG_VALUE, NULL,
+ _("Invalid config: unknown HTTP library "
+ "'%s'"),
+ http_library);
+#endif
+ }
+ }
+
+ if (callbacks->auth_baton)
+ {
+ /* Save auth caching parameters in the auth parameter hash. */
+ if (! store_passwords)
+ svn_auth_set_parameter(callbacks->auth_baton,
+ SVN_AUTH_PARAM_DONT_STORE_PASSWORDS, "");
+
+ svn_auth_set_parameter(callbacks->auth_baton,
+ SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS,
+ store_plaintext_passwords);
+
+ if (! store_pp)
+ svn_auth_set_parameter(callbacks->auth_baton,
+ SVN_AUTH_PARAM_DONT_STORE_SSL_CLIENT_CERT_PP,
+ "");
+
+ svn_auth_set_parameter(callbacks->auth_baton,
+ SVN_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
+ store_pp_plaintext);
+
+ if (! store_auth_creds)
+ svn_auth_set_parameter(callbacks->auth_baton,
+ SVN_AUTH_PARAM_NO_AUTH_CACHE, "");
+ }
+
+ /* Find the library. */
+ for (defn = ra_libraries; defn->ra_name != NULL; ++defn)
+ {
+ const char *scheme;
+
+ if ((scheme = has_scheme_of(defn->schemes, repos_URL)))
+ {
+ svn_ra__init_func_t initfunc = defn->initfunc;
+
+#ifdef CHOOSABLE_DAV_MODULE
+ if (defn->schemes == dav_schemes
+ && strcmp(defn->ra_name, http_library) != 0)
+ continue;
+#endif
+
+ if (! initfunc)
+ SVN_ERR(load_ra_module(&initfunc, NULL, defn->ra_name,
+ sesspool));
+ if (! initfunc)
+ /* Library not found. */
+ continue;
+
+ SVN_ERR(initfunc(svn_ra_version(), &vtable, sesspool));
+
+ 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;
+ }
+ }
+
+ if (vtable == NULL)
+ return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
+ _("Unrecognized URL scheme for '%s'"),
+ repos_URL);
+
+ /* 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;
+
+ /* Ask the library to open the session. */
+ SVN_ERR_W(vtable->open_session(session, &corrected_url, repos_URL,
+ callbacks, callback_baton, config, sesspool),
+ apr_psprintf(pool, "Unable to connect to a repository at URL '%s'",
+ repos_URL));
+
+ /* If the session open stuff detected a server-provided URL
+ correction (a 301 or 302 redirect response during the initial
+ OPTIONS request), then kill the session so the caller can decide
+ what to do. */
+ if (corrected_url_p && corrected_url)
+ {
+ if (! svn_path_is_url(corrected_url))
+ {
+ /* RFC1945 and RFC2616 state that the Location header's
+ value (from whence this CORRECTED_URL ultimately comes),
+ if present, must be an absolute URI. But some Apache
+ versions (those older than 2.2.11, it seems) transmit
+ only the path portion of the URI. See issue #3775 for
+ details. */
+ apr_uri_t corrected_URI = repos_URI;
+ corrected_URI.path = (char *)corrected_url;
+ corrected_url = apr_uri_unparse(pool, &corrected_URI, 0);
+ }
+ *corrected_url_p = svn_uri_canonicalize(corrected_url, pool);
+ svn_pool_destroy(sesspool);
+ return SVN_NO_ERROR;
+ }
+
+ /* Check the UUID. */
+ if (uuid)
+ {
+ const char *repository_uuid;
+
+ SVN_ERR(vtable->get_uuid(session, &repository_uuid, pool));
+ if (strcmp(uuid, repository_uuid) != 0)
+ {
+ /* Duplicate the uuid as it is allocated in sesspool */
+ repository_uuid = apr_pstrdup(pool, repository_uuid);
+ svn_pool_destroy(sesspool);
+ return svn_error_createf(SVN_ERR_RA_UUID_MISMATCH, NULL,
+ _("Repository UUID '%s' doesn't match "
+ "expected UUID '%s'"),
+ repository_uuid, uuid);
+ }
+ }
+
+ *session_p = session;
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *svn_ra_reparent(svn_ra_session_t *session,
+ const char *url,
+ apr_pool_t *pool)
+{
+ const char *repos_root;
+
+ /* Make sure the new URL is in the same repository, so that the
+ implementations don't have to do it. */
+ SVN_ERR(svn_ra_get_repos_root2(session, &repos_root, pool));
+ if (! svn_uri__is_ancestor(repos_root, url))
+ return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
+ _("'%s' isn't in the same repository as '%s'"),
+ url, repos_root);
+
+ return session->vtable->reparent(session, url, pool);
+}
+
+svn_error_t *svn_ra_get_session_url(svn_ra_session_t *session,
+ const char **url,
+ apr_pool_t *pool)
+{
+ return session->vtable->get_session_url(session, url, pool);
+}
+
+svn_error_t *svn_ra_get_path_relative_to_session(svn_ra_session_t *session,
+ const char **rel_path,
+ const char *url,
+ apr_pool_t *pool)
+{
+ const char *sess_url;
+
+ SVN_ERR(session->vtable->get_session_url(session, &sess_url, pool));
+ *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;
+}
+
+svn_error_t *svn_ra_get_path_relative_to_root(svn_ra_session_t *session,
+ const char **rel_path,
+ const char *url,
+ apr_pool_t *pool)
+{
+ const char *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;
+}
+
+svn_error_t *svn_ra_get_latest_revnum(svn_ra_session_t *session,
+ svn_revnum_t *latest_revnum,
+ apr_pool_t *pool)
+{
+ return session->vtable->get_latest_revnum(session, latest_revnum, pool);
+}
+
+svn_error_t *svn_ra_get_dated_revision(svn_ra_session_t *session,
+ svn_revnum_t *revision,
+ apr_time_t tm,
+ apr_pool_t *pool)
+{
+ return session->vtable->get_dated_revision(session, revision, tm, pool);
+}
+
+svn_error_t *svn_ra_change_rev_prop2(svn_ra_session_t *session,
+ svn_revnum_t rev,
+ const char *name,
+ const svn_string_t *const *old_value_p,
+ const svn_string_t *value,
+ apr_pool_t *pool)
+{
+ SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(rev));
+
+ /* If an old value was specified, make sure the server supports
+ * specifying it. */
+ if (old_value_p)
+ {
+ svn_boolean_t has_atomic_revprops;
+
+ SVN_ERR(svn_ra_has_capability(session, &has_atomic_revprops,
+ SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
+ pool));
+
+ if (!has_atomic_revprops)
+ /* API violation. (Should be an ASSERT, but gstein talked me
+ * out of it.) */
+ return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+ _("Specifying 'old_value_p' is not allowed when "
+ "the '%s' capability is not advertised, and "
+ "could indicate a bug in your client"),
+ SVN_RA_CAPABILITY_ATOMIC_REVPROPS);
+ }
+
+ return session->vtable->change_rev_prop(session, rev, name,
+ old_value_p, value, pool);
+}
+
+svn_error_t *svn_ra_rev_proplist(svn_ra_session_t *session,
+ svn_revnum_t rev,
+ apr_hash_t **props,
+ apr_pool_t *pool)
+{
+ SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(rev));
+ return session->vtable->rev_proplist(session, rev, props, pool);
+}
+
+svn_error_t *svn_ra_rev_prop(svn_ra_session_t *session,
+ svn_revnum_t rev,
+ const char *name,
+ svn_string_t **value,
+ apr_pool_t *pool)
+{
+ SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(rev));
+ return session->vtable->rev_prop(session, rev, name, value, pool);
+}
+
+struct ccw_baton
+{
+ svn_commit_callback2_t original_callback;
+ void *original_baton;
+
+ svn_ra_session_t *session;
+};
+
+/* Wrapper which populates the repos_root field of the commit_info struct */
+static svn_error_t *
+commit_callback_wrapper(const svn_commit_info_t *commit_info,
+ void *baton,
+ apr_pool_t *pool)
+{
+ struct ccw_baton *ccwb = baton;
+ svn_commit_info_t *ci = svn_commit_info_dup(commit_info, pool);
+
+ SVN_ERR(svn_ra_get_repos_root2(ccwb->session, &ci->repos_root, pool));
+
+ 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 commit_callback,
+ void *commit_baton,
+ apr_hash_t *lock_tokens,
+ svn_boolean_t keep_locks,
+ apr_pool_t *pool)
+{
+ 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,
+ commit_callback, commit_baton,
+ lock_tokens, keep_locks, pool);
+}
+
+svn_error_t *svn_ra_get_file(svn_ra_session_t *session,
+ const char *path,
+ svn_revnum_t revision,
+ svn_stream_t *stream,
+ svn_revnum_t *fetched_rev,
+ apr_hash_t **props,
+ apr_pool_t *pool)
+{
+ 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_dir2(svn_ra_session_t *session,
+ apr_hash_t **dirents,
+ svn_revnum_t *fetched_rev,
+ apr_hash_t **props,
+ const char *path,
+ svn_revnum_t revision,
+ apr_uint32_t dirent_fields,
+ apr_pool_t *pool)
+{
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(path));
+ return session->vtable->get_dir(session, dirents, fetched_rev, props,
+ path, revision, dirent_fields, pool);
+}
+
+svn_error_t *svn_ra_get_mergeinfo(svn_ra_session_t *session,
+ svn_mergeinfo_catalog_t *catalog,
+ const apr_array_header_t *paths,
+ svn_revnum_t revision,
+ svn_mergeinfo_inheritance_t inherit,
+ svn_boolean_t include_descendants,
+ apr_pool_t *pool)
+{
+ svn_error_t *err;
+ int i;
+
+ /* Validate path format. */
+ for (i = 0; i < paths->nelts; i++)
+ {
+ const char *path = APR_ARRAY_IDX(paths, i, const char *);
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(path));
+ }
+
+ /* Check server Merge Tracking capability. */
+ err = svn_ra__assert_mergeinfo_capable_server(session, NULL, pool);
+ if (err)
+ {
+ *catalog = NULL;
+ return err;
+ }
+
+ return session->vtable->get_mergeinfo(session, catalog, paths,
+ revision, inherit,
+ include_descendants, 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));
+ return session->vtable->do_update(session,
+ reporter, report_baton,
+ revision_to_update_to, update_target,
+ depth, send_copyfrom_args,
+ ignore_ancestry,
+ update_editor, update_baton,
+ result_pool, scratch_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,
+ 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,
+ const svn_ra_reporter3_t **reporter,
+ void **report_baton,
+ const char *status_target,
+ svn_revnum_t revision,
+ svn_depth_t depth,
+ const svn_delta_editor_t *status_editor,
+ void *status_baton,
+ apr_pool_t *pool)
+{
+ SVN_ERR_ASSERT(svn_path_is_empty(status_target)
+ || svn_path_is_single_path_component(status_target));
+ return session->vtable->do_status(session,
+ reporter, report_baton,
+ status_target, revision, depth,
+ status_editor, status_baton, pool);
+}
+
+svn_error_t *svn_ra_do_diff3(svn_ra_session_t *session,
+ const svn_ra_reporter3_t **reporter,
+ void **report_baton,
+ svn_revnum_t revision,
+ const char *diff_target,
+ svn_depth_t depth,
+ svn_boolean_t ignore_ancestry,
+ svn_boolean_t text_deltas,
+ const char *versus_url,
+ const svn_delta_editor_t *diff_editor,
+ 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,
+ depth, ignore_ancestry,
+ text_deltas, versus_url, diff_editor,
+ diff_baton, pool);
+}
+
+svn_error_t *svn_ra_get_log2(svn_ra_session_t *session,
+ const apr_array_header_t *paths,
+ svn_revnum_t start,
+ svn_revnum_t end,
+ int limit,
+ svn_boolean_t discover_changed_paths,
+ svn_boolean_t strict_node_history,
+ svn_boolean_t include_merged_revisions,
+ const apr_array_header_t *revprops,
+ svn_log_entry_receiver_t receiver,
+ void *receiver_baton,
+ apr_pool_t *pool)
+{
+ if (paths)
+ {
+ int i;
+ for (i = 0; i < paths->nelts; i++)
+ {
+ const char *path = APR_ARRAY_IDX(paths, i, const char *);
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(path));
+ }
+ }
+
+ if (include_merged_revisions)
+ SVN_ERR(svn_ra__assert_mergeinfo_capable_server(session, NULL, pool));
+
+ return session->vtable->get_log(session, paths, start, end, limit,
+ discover_changed_paths, strict_node_history,
+ include_merged_revisions, revprops,
+ receiver, receiver_baton, pool);
+}
+
+svn_error_t *svn_ra_check_path(svn_ra_session_t *session,
+ const char *path,
+ svn_revnum_t revision,
+ svn_node_kind_t *kind,
+ apr_pool_t *pool)
+{
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(path));
+ return session->vtable->check_path(session, path, revision, kind, pool);
+}
+
+svn_error_t *svn_ra_stat(svn_ra_session_t *session,
+ const char *path,
+ svn_revnum_t revision,
+ svn_dirent_t **dirent,
+ apr_pool_t *pool)
+{
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(path));
+ return session->vtable->stat(session, path, revision, dirent, pool);
+}
+
+svn_error_t *svn_ra_get_uuid2(svn_ra_session_t *session,
+ const char **uuid,
+ apr_pool_t *pool)
+{
+ SVN_ERR(session->vtable->get_uuid(session, uuid, pool));
+ *uuid = *uuid ? apr_pstrdup(pool, *uuid) : NULL;
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *svn_ra_get_uuid(svn_ra_session_t *session,
+ const char **uuid,
+ apr_pool_t *pool)
+{
+ return session->vtable->get_uuid(session, uuid, pool);
+}
+
+svn_error_t *svn_ra_get_repos_root2(svn_ra_session_t *session,
+ const char **url,
+ apr_pool_t *pool)
+{
+ SVN_ERR(session->vtable->get_repos_root(session, url, pool));
+ *url = *url ? apr_pstrdup(pool, *url) : NULL;
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *svn_ra_get_repos_root(svn_ra_session_t *session,
+ const char **url,
+ apr_pool_t *pool)
+{
+ return session->vtable->get_repos_root(session, url, pool);
+}
+
+svn_error_t *svn_ra_get_locations(svn_ra_session_t *session,
+ apr_hash_t **locations,
+ const char *path,
+ svn_revnum_t peg_revision,
+ const apr_array_header_t *location_revisions,
+ apr_pool_t *pool)
+{
+ svn_error_t *err;
+
+ 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))
+ {
+ svn_error_clear(err);
+
+ /* Do it the slow way, using get-logs, for older servers. */
+ err = svn_ra__locations_from_log(session, locations, path,
+ peg_revision, location_revisions,
+ pool);
+ }
+ return err;
+}
+
+svn_error_t *
+svn_ra_get_location_segments(svn_ra_session_t *session,
+ const char *path,
+ svn_revnum_t peg_revision,
+ svn_revnum_t start_rev,
+ svn_revnum_t end_rev,
+ svn_location_segment_receiver_t receiver,
+ void *receiver_baton,
+ apr_pool_t *pool)
+{
+ svn_error_t *err;
+
+ 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);
+ if (err && (err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED))
+ {
+ svn_error_clear(err);
+
+ /* Do it the slow way, using get-logs, for older servers. */
+ err = svn_ra__location_segments_from_log(session, path,
+ peg_revision, start_rev,
+ end_rev, receiver,
+ receiver_baton, pool);
+ }
+ return err;
+}
+
+svn_error_t *svn_ra_get_file_revs2(svn_ra_session_t *session,
+ const char *path,
+ svn_revnum_t start,
+ svn_revnum_t end,
+ svn_boolean_t include_merged_revisions,
+ svn_file_rev_handler_t handler,
+ void *handler_baton,
+ apr_pool_t *pool)
+{
+ svn_error_t *err;
+
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(path));
+
+ if (include_merged_revisions)
+ SVN_ERR(svn_ra__assert_mergeinfo_capable_server(session, NULL, pool));
+
+ err = session->vtable->get_file_revs(session, path, start, end,
+ include_merged_revisions,
+ handler, handler_baton, pool);
+ if (err && (err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED))
+ {
+ svn_error_clear(err);
+
+ /* Do it the slow way, using get-logs, for older servers. */
+ err = svn_ra__file_revs_from_log(session, path, start, end,
+ handler, handler_baton, pool);
+ }
+ return err;
+}
+
+svn_error_t *svn_ra_lock(svn_ra_session_t *session,
+ apr_hash_t *path_revs,
+ const char *comment,
+ svn_boolean_t steal_lock,
+ svn_ra_lock_callback_t lock_func,
+ void *lock_baton,
+ apr_pool_t *pool)
+{
+ apr_hash_index_t *hi;
+
+ for (hi = apr_hash_first(pool, path_revs); hi; hi = apr_hash_next(hi))
+ {
+ const char *path = svn__apr_hash_index_key(hi);
+
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(path));
+ }
+
+ if (comment && ! svn_xml_is_xml_safe(comment, strlen(comment)))
+ return svn_error_create
+ (SVN_ERR_XML_UNESCAPABLE_DATA, NULL,
+ _("Lock comment contains illegal characters"));
+
+ return session->vtable->lock(session, path_revs, comment, steal_lock,
+ lock_func, lock_baton, pool);
+}
+
+svn_error_t *svn_ra_unlock(svn_ra_session_t *session,
+ apr_hash_t *path_tokens,
+ svn_boolean_t break_lock,
+ svn_ra_lock_callback_t lock_func,
+ void *lock_baton,
+ apr_pool_t *pool)
+{
+ apr_hash_index_t *hi;
+
+ for (hi = apr_hash_first(pool, path_tokens); hi; hi = apr_hash_next(hi))
+ {
+ const char *path = svn__apr_hash_index_key(hi);
+
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(path));
+ }
+
+ return session->vtable->unlock(session, path_tokens, break_lock,
+ lock_func, lock_baton, pool);
+}
+
+svn_error_t *svn_ra_get_lock(svn_ra_session_t *session,
+ svn_lock_t **lock,
+ const char *path,
+ apr_pool_t *pool)
+{
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(path));
+ return session->vtable->get_lock(session, lock, path, pool);
+}
+
+svn_error_t *svn_ra_get_locks2(svn_ra_session_t *session,
+ apr_hash_t **locks,
+ const char *path,
+ svn_depth_t depth,
+ apr_pool_t *pool)
+{
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(path));
+ SVN_ERR_ASSERT((depth == svn_depth_empty) ||
+ (depth == svn_depth_files) ||
+ (depth == svn_depth_immediates) ||
+ (depth == svn_depth_infinity));
+ return session->vtable->get_locks(session, locks, path, depth, pool);
+}
+
+svn_error_t *svn_ra_get_locks(svn_ra_session_t *session,
+ apr_hash_t **locks,
+ const char *path,
+ apr_pool_t *pool)
+{
+ return svn_ra_get_locks2(session, locks, path, svn_depth_infinity, pool);
+}
+
+svn_error_t *svn_ra_replay(svn_ra_session_t *session,
+ svn_revnum_t revision,
+ svn_revnum_t low_water_mark,
+ svn_boolean_t text_deltas,
+ const svn_delta_editor_t *editor,
+ void *edit_baton,
+ apr_pool_t *pool)
+{
+ return session->vtable->replay(session, revision, low_water_mark,
+ text_deltas, editor, edit_baton, pool);
+}
+
+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,
+ 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 *pool)
+{
+ svn_error_t *err =
+ session->vtable->replay_range(session, start_revision, end_revision,
+ low_water_mark, text_deltas,
+ revstart_func, revfinish_func,
+ replay_baton, pool);
+
+ 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));
+}
+
+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 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,
+ svn_boolean_t *has,
+ const char *capability,
+ apr_pool_t *pool)
+{
+ return session->vtable->has_capability(session, has, capability, pool);
+}
+
+svn_error_t *
+svn_ra_get_deleted_rev(svn_ra_session_t *session,
+ const char *path,
+ svn_revnum_t peg_revision,
+ svn_revnum_t end_revision,
+ svn_revnum_t *revision_deleted,
+ apr_pool_t *pool)
+{
+ svn_error_t *err;
+
+ /* Path must be relative. */
+ 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,
+ _("Invalid peg revision %ld"), peg_revision);
+ if (!SVN_IS_VALID_REVNUM(end_revision))
+ return svn_error_createf(SVN_ERR_CLIENT_BAD_REVISION, NULL,
+ _("Invalid end revision %ld"), end_revision);
+ if (end_revision <= peg_revision)
+ return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL,
+ _("Peg revision must precede end revision"));
+ err = session->vtable->get_deleted_rev(session, path,
+ peg_revision,
+ end_revision,
+ revision_deleted,
+ pool);
+ if (err && (err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE))
+ {
+ svn_error_clear(err);
+
+ /* Do it the slow way, using get-logs, for older servers. */
+ err = svn_ra__get_deleted_rev_from_log(session, path, peg_revision,
+ end_revision, revision_deleted,
+ pool);
+ }
+ 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 *
+svn_ra_print_modules(svn_stringbuf_t *output,
+ apr_pool_t *pool)
+{
+ const struct ra_lib_defn *defn;
+ const char * const *schemes;
+ svn_ra__init_func_t initfunc;
+ const svn_ra__vtable_t *vtable;
+ apr_pool_t *iterpool = svn_pool_create(pool);
+
+ for (defn = ra_libraries; defn->ra_name != NULL; ++defn)
+ {
+ char *line;
+
+ svn_pool_clear(iterpool);
+
+ initfunc = defn->initfunc;
+ if (! initfunc)
+ SVN_ERR(load_ra_module(&initfunc, NULL, defn->ra_name,
+ iterpool));
+
+ if (initfunc)
+ {
+ SVN_ERR(initfunc(svn_ra_version(), &vtable, iterpool));
+
+ SVN_ERR(check_ra_version(vtable->get_version(), defn->ra_name));
+
+ /* Note: if you change the formatting of the description,
+ bear in mind that ra_svn's description has multiple lines when
+ built with SASL. */
+ line = apr_psprintf(iterpool, "* ra_%s : %s\n",
+ defn->ra_name,
+ vtable->get_description());
+ svn_stringbuf_appendcstr(output, line);
+
+ for (schemes = vtable->get_schemes(iterpool); *schemes != NULL;
+ ++schemes)
+ {
+ line = apr_psprintf(iterpool, _(" - handles '%s' scheme\n"),
+ *schemes);
+ svn_stringbuf_appendcstr(output, line);
+ }
+ }
+ }
+
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_ra_print_ra_libraries(svn_stringbuf_t **descriptions,
+ void *ra_baton,
+ apr_pool_t *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)
+{
+ SVN_VERSION_BODY;
+}
+
+
+/*** Compatibility Interfaces **/
+svn_error_t *
+svn_ra_init_ra_libs(void **ra_baton,
+ apr_pool_t *pool)
+{
+ *ra_baton = pool;
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_ra_get_ra_library(svn_ra_plugin_t **library,
+ void *ra_baton,
+ const char *url,
+ apr_pool_t *pool)
+{
+ const struct ra_lib_defn *defn;
+ apr_pool_t *load_pool = ra_baton;
+ apr_hash_t *ht = apr_hash_make(pool);
+
+ /* Figure out which RA library key matches URL. */
+ for (defn = ra_libraries; defn->ra_name != NULL; ++defn)
+ {
+ const char *scheme;
+ if ((scheme = has_scheme_of(defn->schemes, url)))
+ {
+ svn_ra_init_func_t compat_initfunc = defn->compat_initfunc;
+
+ if (! compat_initfunc)
+ {
+ SVN_ERR(load_ra_module
+ (NULL, &compat_initfunc, defn->ra_name, load_pool));
+ }
+ if (! compat_initfunc)
+ {
+ continue;
+ }
+
+ SVN_ERR(compat_initfunc(SVN_RA_ABI_VERSION, load_pool, ht));
+
+ *library = svn_hash_gets(ht, scheme);
+
+ /* The library may support just a subset of the schemes listed,
+ so we have to check here too. */
+ if (! *library)
+ break;
+
+ return check_ra_version((*library)->get_version(), scheme);
+ }
+ }
+
+ /* Couldn't find a match... */
+ *library = NULL;
+ return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
+ _("Unrecognized URL scheme '%s'"), url);
+}
+
+/* For each libsvn_ra_foo library that is not linked in, provide a default
+ implementation for svn_ra_foo_init which returns a "not implemented"
+ error. */
+
+#ifndef SVN_LIBSVN_CLIENT_LINKS_RA_NEON
+svn_error_t *
+svn_ra_dav_init(int abi_version,
+ apr_pool_t *pool,
+ apr_hash_t *hash)
+{
+ return svn_error_create(SVN_ERR_RA_NOT_IMPLEMENTED, NULL, NULL);
+}
+#endif /* ! SVN_LIBSVN_CLIENT_LINKS_RA_NEON */
+
+#ifndef SVN_LIBSVN_CLIENT_LINKS_RA_SVN
+svn_error_t *
+svn_ra_svn_init(int abi_version,
+ apr_pool_t *pool,
+ apr_hash_t *hash)
+{
+ return svn_error_create(SVN_ERR_RA_NOT_IMPLEMENTED, NULL, NULL);
+}
+#endif /* ! SVN_LIBSVN_CLIENT_LINKS_RA_SVN */
+
+#ifndef SVN_LIBSVN_CLIENT_LINKS_RA_LOCAL
+svn_error_t *
+svn_ra_local_init(int abi_version,
+ apr_pool_t *pool,
+ apr_hash_t *hash)
+{
+ return svn_error_create(SVN_ERR_RA_NOT_IMPLEMENTED, NULL, NULL);
+}
+#endif /* ! SVN_LIBSVN_CLIENT_LINKS_RA_LOCAL */
+
+#ifndef SVN_LIBSVN_CLIENT_LINKS_RA_SERF
+svn_error_t *
+svn_ra_serf_init(int abi_version,
+ apr_pool_t *pool,
+ apr_hash_t *hash)
+{
+ return svn_error_create(SVN_ERR_RA_NOT_IMPLEMENTED, NULL, NULL);
+}
+#endif /* ! SVN_LIBSVN_CLIENT_LINKS_RA_SERF */
OpenPOWER on IntegriCloud