2
* ra_loader.c: logic for loading different RA library implementations
4
* ====================================================================
5
* Copyright (c) 2000-2004 CollabNet. All rights reserved.
7
* This software is licensed as described in the file COPYING, which
8
* you should have received as part of this distribution. The terms
9
* are also available at http://subversion.tigris.org/license-1.html.
10
* If newer versions of this license are posted there, you may use a
11
* newer version instead, at your option.
13
* This software consists of voluntary contributions made by many
14
* individuals. For exact contribution history, see the revision
15
* history and logs, available at http://subversion.tigris.org/.
16
* ====================================================================
19
/* ==================================================================== */
25
#include <apr_strings.h>
26
#include <apr_pools.h>
30
#include "svn_version.h"
31
#include "svn_error.h"
32
#include "svn_pools.h"
35
#include "ra_loader.h"
36
#include "svn_private_config.h"
39
/* ### this file maps URL schemes to particular RA libraries. This is not
40
### entirely correct, as a single scheme could potentially be served
41
### by more than one loader. However, we can ignore that until we
42
### actually run into a conflict within the scheme portion of a URL. */
45
/* These are the URI schemes that the respective libraries *may* support.
46
* The schemes actually supported may be a subset of the schemes listed below.
47
* This can't be determine until the library is loaded.
48
* (Currently, this applies to the https scheme of ra_dav, which is only
49
* available if SSL is supported.) */
50
static const char * const dav_schemes[] = { "http", "https", NULL };
51
static const char * const svn_schemes[] = { "svn", NULL };
52
static const char * const local_schemes[] = { "file", NULL };
54
static const struct ra_lib_defn {
55
/* the name of this RA library (e.g. "dav" or "local") */
58
const char * const *schemes;
59
/* the initialization function if linked in; otherwise, NULL */
60
svn_ra__init_func_t initfunc;
61
svn_ra_init_func_t compat_initfunc;
66
#ifdef SVN_LIBSVN_CLIENT_LINKS_RA_DAV
75
#ifdef SVN_LIBSVN_CLIENT_LINKS_RA_SVN
84
#ifdef SVN_LIBSVN_CLIENT_LINKS_RA_LOCAL
90
/* ADD NEW RA IMPLEMENTATIONS HERE (as they're written) */
96
/* Ensure that the RA library NAME is loaded.
98
* If FUNC is non-NULL, set *FUNC to the address of the svn_ra_NAME__init
99
* function of the library.
101
* If COMPAT_FUNC is non-NULL, set *COMPAT_FUNC to the address of the
102
* svn_ra_NAME_init compatibility init function of the library.
104
* ### todo: Any RA libraries implemented from this point forward
105
* ### don't really need an svn_ra_NAME_init compatibility function.
106
* ### Currently, load_ra_module() will error if no such function is
107
* ### found, but it might be more friendly to simply set *COMPAT_FUNC
108
* ### to null (assuming COMPAT_FUNC itself is non-null).
111
load_ra_module (svn_ra__init_func_t *func,
112
svn_ra_init_func_t *compat_func,
113
const char *ra_name, apr_pool_t *pool)
122
apr_dso_handle_t *dso;
123
apr_dso_handle_sym_t symbol;
125
const char *funcname;
126
const char *compat_funcname;
129
libname = apr_psprintf (pool, "libsvn_ra_%s-%d.so.0",
130
ra_name, SVN_VER_MAJOR);
131
funcname = apr_psprintf (pool, "svn_ra_%s__init", ra_name);
132
compat_funcname = apr_psprintf (pool, "svn_ra_%s_init", ra_name);
134
/* find/load the specified library */
135
status = apr_dso_load (&dso, libname, pool);
140
apr_dso_error(dso, errbuf, sizeof(errbuf));
142
fprintf(stderr, "DSO error: %s\n", errbuf);
145
/* Just ignore the error. Assume the library isn't present */
148
/* note: the library will be unloaded at pool cleanup */
150
/* find the initialization routines */
153
status = apr_dso_sym (&symbol, dso, funcname);
156
return svn_error_wrap_apr (status,
157
_("'%s' does not define '%s()'"),
161
*func = (svn_ra__init_func_t) symbol;
166
status = apr_dso_sym (&symbol, dso, compat_funcname);
169
return svn_error_wrap_apr (status,
170
_("'%s' does not define '%s()'"),
171
libname, compat_funcname);
174
*compat_func = (svn_ra_init_func_t) symbol;
177
#endif /* APR_HAS_DSO */
182
/* If DEFN may support URL, return the scheme. Else, return NULL. */
184
has_scheme_of (const struct ra_lib_defn *defn, const char *url)
186
const char * const *schemes;
189
for (schemes = defn->schemes; *schemes != NULL; ++schemes)
191
const char *scheme = *schemes;
192
len = strlen (scheme);
193
/* Case-insensitive comparison, per RFC 2396 section 3.1. Allow
194
URL to contain a trailing "+foo" section in the scheme, since
195
that's how we specify tunnel schemes in ra_svn. */
196
if (strncasecmp (scheme, url, len) == 0 &&
197
(url[len] == ':' || url[len] == '+'))
204
/* Return an error if RA_VERSION doesn't match the version of this library.
205
Use SCHEME in the error message to describe the library that was loaded. */
207
check_ra_version (const svn_version_t *ra_version, const char *scheme)
209
const svn_version_t *my_version = svn_ra_version ();
210
if (!svn_ver_equal (my_version, ra_version))
211
return svn_error_createf (SVN_ERR_VERSION_MISMATCH, NULL,
212
_("Mismatched RA version for '%s':"
214
" expected %d.%d.%d%s"),
216
my_version->major, my_version->minor,
217
my_version->patch, my_version->tag,
218
ra_version->major, ra_version->minor,
219
ra_version->patch, ra_version->tag);
224
/* -------------------------------------------------------------- */
226
/*** Public Interfaces ***/
228
svn_error_t *svn_ra_initialize (apr_pool_t *pool)
233
svn_error_t *svn_ra_open (svn_ra_session_t **session_p,
234
const char *repos_URL,
235
const svn_ra_callbacks_t *callbacks,
236
void *callback_baton,
240
svn_ra_session_t *session;
241
const struct ra_lib_defn *defn;
242
const svn_ra__vtable_t *vtable = NULL;
244
/* Find the library. */
245
for (defn = ra_libraries; defn->ra_name != NULL; ++defn)
249
if ((scheme = has_scheme_of (defn, repos_URL)))
251
svn_ra__init_func_t initfunc = defn->initfunc;
254
SVN_ERR (load_ra_module (&initfunc, NULL, defn->ra_name,
257
/* Library not found. */
260
SVN_ERR (initfunc (svn_ra_version (), &vtable, pool));
262
SVN_ERR (check_ra_version (vtable->get_version (), scheme));
267
return svn_error_createf (SVN_ERR_RA_ILLEGAL_URL, NULL,
268
_("Unrecognized URL scheme for '%s'"),
271
/* Create the session object. */
272
session = apr_pcalloc (pool, sizeof (*session));
273
session->vtable = vtable;
274
session->pool = pool;
276
/* Ask the library to open the session. */
277
SVN_ERR (vtable->open (session, repos_URL, callbacks, callback_baton,
280
*session_p = session;
284
svn_error_t *svn_ra_get_latest_revnum (svn_ra_session_t *session,
285
svn_revnum_t *latest_revnum,
288
return session->vtable->get_latest_revnum (session, latest_revnum, pool);
291
svn_error_t *svn_ra_get_dated_revision (svn_ra_session_t *session,
292
svn_revnum_t *revision,
296
return session->vtable->get_dated_revision (session, revision, tm, pool);
299
svn_error_t *svn_ra_change_rev_prop (svn_ra_session_t *session,
302
const svn_string_t *value,
305
return session->vtable->change_rev_prop (session, rev, name, value, pool);
308
svn_error_t *svn_ra_rev_proplist (svn_ra_session_t *session,
313
return session->vtable->rev_proplist (session, rev, props, pool);
316
svn_error_t *svn_ra_rev_prop (svn_ra_session_t *session,
319
svn_string_t **value,
322
return session->vtable->rev_prop (session, rev, name, value, pool);
325
svn_error_t *svn_ra_get_commit_editor (svn_ra_session_t *session,
326
const svn_delta_editor_t **editor,
329
svn_commit_callback_t callback,
330
void *callback_baton,
331
apr_hash_t *lock_tokens,
332
svn_boolean_t keep_locks,
335
return session->vtable->get_commit_editor (session, editor, edit_baton,
336
log_msg, callback, callback_baton,
337
lock_tokens, keep_locks, pool);
340
svn_error_t *svn_ra_get_file (svn_ra_session_t *session,
342
svn_revnum_t revision,
343
svn_stream_t *stream,
344
svn_revnum_t *fetched_rev,
348
return session->vtable->get_file (session, path, revision, stream,
349
fetched_rev, props, pool);
352
svn_error_t *svn_ra_get_dir (svn_ra_session_t *session,
354
svn_revnum_t revision,
355
apr_hash_t **dirents,
356
svn_revnum_t *fetched_rev,
360
return session->vtable->get_dir (session, path, revision, dirents,
361
fetched_rev, props, pool);
364
svn_error_t *svn_ra_do_update (svn_ra_session_t *session,
365
const svn_ra_reporter2_t **reporter,
367
svn_revnum_t revision_to_update_to,
368
const char *update_target,
369
svn_boolean_t recurse,
370
const svn_delta_editor_t *update_editor,
374
return session->vtable->do_update (session, reporter, report_baton,
375
revision_to_update_to, update_target,
376
recurse, update_editor, update_baton,
380
svn_error_t *svn_ra_do_switch (svn_ra_session_t *session,
381
const svn_ra_reporter2_t **reporter,
383
svn_revnum_t revision_to_switch_to,
384
const char *switch_target,
385
svn_boolean_t recurse,
386
const char *switch_url,
387
const svn_delta_editor_t *switch_editor,
391
return session->vtable->do_switch (session, reporter, report_baton,
392
revision_to_switch_to, switch_target,
393
recurse, switch_url, switch_editor,
397
svn_error_t *svn_ra_do_status (svn_ra_session_t *session,
398
const svn_ra_reporter2_t **reporter,
400
const char *status_target,
401
svn_revnum_t revision,
402
svn_boolean_t recurse,
403
const svn_delta_editor_t *status_editor,
407
return session->vtable->do_status (session, reporter, report_baton,
408
status_target, revision, recurse,
409
status_editor, status_baton, pool);
412
svn_error_t *svn_ra_do_diff (svn_ra_session_t *session,
413
const svn_ra_reporter2_t **reporter,
415
svn_revnum_t revision,
416
const char *diff_target,
417
svn_boolean_t recurse,
418
svn_boolean_t ignore_ancestry,
419
const char *versus_url,
420
const svn_delta_editor_t *diff_editor,
424
return session->vtable->do_diff (session, reporter, report_baton, revision,
425
diff_target, recurse, ignore_ancestry,
426
versus_url, diff_editor, diff_baton, pool);
429
svn_error_t *svn_ra_get_log (svn_ra_session_t *session,
430
const apr_array_header_t *paths,
434
svn_boolean_t discover_changed_paths,
435
svn_boolean_t strict_node_history,
436
svn_log_message_receiver_t receiver,
437
void *receiver_baton,
440
return session->vtable->get_log (session, paths, start, end, limit,
441
discover_changed_paths, strict_node_history,
442
receiver, receiver_baton, pool);
445
svn_error_t *svn_ra_check_path (svn_ra_session_t *session,
447
svn_revnum_t revision,
448
svn_node_kind_t *kind,
451
return session->vtable->check_path (session, path, revision, kind, pool);
454
svn_error_t *svn_ra_stat (svn_ra_session_t *session,
456
svn_revnum_t revision,
457
svn_dirent_t **dirent,
460
return session->vtable->stat (session, path, revision, dirent, pool);
463
svn_error_t *svn_ra_get_uuid (svn_ra_session_t *session,
467
return session->vtable->get_uuid (session, uuid, pool);
470
svn_error_t *svn_ra_get_repos_root (svn_ra_session_t *session,
474
return session->vtable->get_repos_root (session, url, pool);
477
svn_error_t *svn_ra_get_locations (svn_ra_session_t *session,
478
apr_hash_t **locations,
480
svn_revnum_t peg_revision,
481
apr_array_header_t *location_revisions,
484
return session->vtable->get_locations (session, locations, path,
485
peg_revision, location_revisions,
489
svn_error_t *svn_ra_get_file_revs (svn_ra_session_t *session,
493
svn_ra_file_rev_handler_t handler,
497
return session->vtable->get_file_revs (session, path, start, end, handler,
498
handler_baton, pool);
501
svn_error_t *svn_ra_lock (svn_ra_session_t *session,
502
apr_hash_t *path_revs,
504
svn_boolean_t steal_lock,
505
svn_ra_lock_callback_t lock_func,
509
if (comment && ! svn_xml_is_xml_safe(comment, strlen(comment)))
510
return svn_error_create
511
(SVN_ERR_XML_UNESCAPABLE_DATA, NULL,
512
_("Lock comment has illegal characters"));
514
return session->vtable->lock (session, path_revs, comment, steal_lock,
515
lock_func, lock_baton, pool);
518
svn_error_t *svn_ra_unlock (svn_ra_session_t *session,
519
apr_hash_t *path_tokens,
520
svn_boolean_t break_lock,
521
svn_ra_lock_callback_t lock_func,
525
return session->vtable->unlock (session, path_tokens, break_lock,
526
lock_func, lock_baton, pool);
529
svn_error_t *svn_ra_get_lock (svn_ra_session_t *session,
534
return session->vtable->get_lock (session, lock, path, pool);
537
svn_error_t *svn_ra_get_locks (svn_ra_session_t *session,
542
return session->vtable->get_locks (session, locks, path, pool);
548
svn_ra_print_modules (svn_stringbuf_t *output,
551
const struct ra_lib_defn *defn;
552
const char * const *schemes;
553
svn_ra__init_func_t initfunc;
554
const svn_ra__vtable_t *vtable;
555
apr_pool_t *iterpool = svn_pool_create (pool);
557
for (defn = ra_libraries; defn->ra_name != NULL; ++defn)
561
svn_pool_clear (iterpool);
563
initfunc = defn->initfunc;
565
SVN_ERR (load_ra_module (&initfunc, NULL, defn->ra_name,
570
SVN_ERR (initfunc (svn_ra_version(), &vtable, iterpool));
572
SVN_ERR (check_ra_version (vtable->get_version (), defn->ra_name));
574
line = apr_psprintf (iterpool, "* ra_%s : %s\n",
576
vtable->get_description());
577
svn_stringbuf_appendcstr (output, line);
579
for (schemes = vtable->get_schemes(iterpool); *schemes != NULL;
582
line = apr_psprintf (iterpool, _(" - handles '%s' scheme\n"),
584
svn_stringbuf_appendcstr (output, line);
589
svn_pool_destroy (iterpool);
596
svn_ra_print_ra_libraries (svn_stringbuf_t **descriptions,
600
*descriptions = svn_stringbuf_create ("", pool);
601
return svn_ra_print_modules (*descriptions, pool);
605
/* Return the library version number. */
606
const svn_version_t *
607
svn_ra_version (void)
613
/*** Compatibility Interfaces **/
615
svn_ra_init_ra_libs (void **ra_baton,
623
svn_ra_get_ra_library (svn_ra_plugin_t **library,
628
const struct ra_lib_defn *defn;
629
apr_pool_t *load_pool = ra_baton;
630
apr_hash_t *ht = apr_hash_make (pool);
632
/* Figure out which RA library key matches URL. */
633
for (defn = ra_libraries; defn->ra_name != NULL; ++defn)
636
if ((scheme = has_scheme_of (defn, url)))
638
svn_ra_init_func_t compat_initfunc = defn->compat_initfunc;
640
if (! compat_initfunc)
642
SVN_ERR (load_ra_module
643
(NULL, &compat_initfunc, defn->ra_name, load_pool));
645
if (! compat_initfunc)
650
SVN_ERR (compat_initfunc (SVN_RA_ABI_VERSION, load_pool, ht));
652
*library = apr_hash_get (ht, scheme, APR_HASH_KEY_STRING);
654
/* The library may support just a subset of the schemes listed,
655
so we have to check here too. */
659
SVN_ERR (check_ra_version ((*library)->get_version (), scheme));
665
/* Couldn't find a match... */
667
return svn_error_createf (SVN_ERR_RA_ILLEGAL_URL, NULL,
668
_("Unrecognized URL scheme '%s'"), url);