Change the format of the revprops block sent in svnserve for
[svn.git] / subversion / libsvn_fs / fs-loader.c
blob62b3031131616d0f7742a901034933f9602bf739
1 /*
2 * fs_loader.c: Front-end to the various FS back ends
4 * ====================================================================
5 * Copyright (c) 2000-2008 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 * ====================================================================
20 #include <string.h>
21 #include <apr.h>
22 #include <apr_hash.h>
23 #include <apr_thread_mutex.h>
24 #include <apr_uuid.h>
26 #include "svn_types.h"
27 #include "svn_dso.h"
28 #include "svn_version.h"
29 #include "svn_fs.h"
30 #include "svn_path.h"
31 #include "svn_xml.h"
32 #include "svn_pools.h"
33 #include "svn_string.h"
34 #include "svn_private_config.h"
36 #include "fs-loader.h"
38 /* This is defined by configure on platforms which use configure, but
39 we need to define a fallback for Windows. */
40 #ifndef DEFAULT_FS_TYPE
41 #define DEFAULT_FS_TYPE "fsfs"
42 #endif
44 #define FS_TYPE_FILENAME "fs-type"
46 /* A pool common to all FS objects. See the documentation on the
47 open/create functions in fs-loader.h and for svn_fs_initialize(). */
48 static apr_pool_t *common_pool;
49 #if APR_HAS_THREADS
50 static apr_thread_mutex_t *common_pool_lock;
51 #endif
54 /* --- Utility functions for the loader --- */
56 static const struct fs_type_defn {
57 const char *fs_type;
58 const char *fsap_name;
59 fs_init_func_t initfunc;
60 } fs_modules[] = {
62 SVN_FS_TYPE_BDB, "base",
63 #ifdef SVN_LIBSVN_FS_LINKS_FS_BASE
64 svn_fs_base__init
65 #endif
69 SVN_FS_TYPE_FSFS, "fs",
70 #ifdef SVN_LIBSVN_FS_LINKS_FS_FS
71 svn_fs_fs__init
72 #endif
75 { NULL }
78 static svn_error_t *
79 load_module(fs_init_func_t *initfunc, const char *name, apr_pool_t *pool)
81 *initfunc = NULL;
83 #if APR_HAS_DSO
85 apr_dso_handle_t *dso;
86 apr_dso_handle_sym_t symbol;
87 const char *libname;
88 const char *funcname;
89 apr_status_t status;
91 libname = apr_psprintf(pool, "libsvn_fs_%s-%d.so.0",
92 name, SVN_VER_MAJOR);
93 funcname = apr_psprintf(pool, "svn_fs_%s__init", name);
95 /* Find/load the specified library. If we get an error, assume
96 the library doesn't exist. The library will be unloaded when
97 pool is destroyed. */
98 SVN_ERR(svn_dso_load(&dso, libname));
99 if (! dso)
100 return SVN_NO_ERROR;
102 /* find the initialization routine */
103 status = apr_dso_sym(&symbol, dso, funcname);
104 if (status)
105 return svn_error_wrap_apr(status, _("'%s' does not define '%s()'"),
106 libname, funcname);
108 *initfunc = (fs_init_func_t) symbol;
110 #endif /* APR_HAS_DSO */
112 return SVN_NO_ERROR;
115 static svn_error_t *
116 acquire_fs_mutex(void)
118 #if APR_HAS_THREADS
119 apr_status_t status;
120 status = apr_thread_mutex_lock(common_pool_lock);
121 if (status)
122 return svn_error_wrap_apr(status, _("Can't grab FS mutex"));
123 #endif
124 return SVN_NO_ERROR;
127 static svn_error_t *
128 release_fs_mutex(void)
130 #if APR_HAS_THREADS
131 apr_status_t status;
132 status = apr_thread_mutex_unlock(common_pool_lock);
133 if (status)
134 return svn_error_wrap_apr(status, _("Can't ungrab FS mutex"));
135 #endif
136 return SVN_NO_ERROR;
139 /* Fetch a library vtable by a pointer into the library definitions array. */
140 static svn_error_t *
141 get_library_vtable_direct(fs_library_vtable_t **vtable,
142 const struct fs_type_defn *fst,
143 apr_pool_t *pool)
145 fs_init_func_t initfunc = NULL;
146 const svn_version_t *my_version = svn_fs_version();
147 const svn_version_t *fs_version;
149 initfunc = fst->initfunc;
150 if (! initfunc)
151 SVN_ERR(load_module(&initfunc, fst->fsap_name, pool));
153 if (! initfunc)
154 return svn_error_createf(SVN_ERR_FS_UNKNOWN_FS_TYPE, NULL,
155 _("Failed to load module for FS type '%s'"),
156 fst->fs_type);
159 svn_error_t *err;
160 svn_error_t *err2;
162 /* Per our API compatibility rules, we cannot ensure that
163 svn_fs_initialize is called by the application. If not, we
164 cannot create the common pool and lock in a thread-safe fashion,
165 nor can we clean up the common pool if libsvn_fs is dynamically
166 unloaded. This function makes a best effort by creating the
167 common pool as a child of the global pool; the window of failure
168 due to thread collision is small. */
169 if (!common_pool)
170 SVN_ERR(svn_fs_initialize(NULL));
172 /* Invoke the FS module's initfunc function with the common
173 pool protected by a lock. */
174 SVN_ERR(acquire_fs_mutex());
175 err = initfunc(my_version, vtable, common_pool);
176 err2 = release_fs_mutex();
177 if (err)
179 svn_error_clear(err2);
180 return err;
182 if (err2)
183 return err2;
185 fs_version = (*vtable)->get_version();
186 if (!svn_ver_equal(my_version, fs_version))
187 return svn_error_createf(SVN_ERR_VERSION_MISMATCH, NULL,
188 _("Mismatched FS module version for '%s':"
189 " found %d.%d.%d%s,"
190 " expected %d.%d.%d%s"),
191 fst->fs_type,
192 my_version->major, my_version->minor,
193 my_version->patch, my_version->tag,
194 fs_version->major, fs_version->minor,
195 fs_version->patch, fs_version->tag);
196 return SVN_NO_ERROR;
199 /* Fetch a library vtable by FS type. */
200 static svn_error_t *
201 get_library_vtable(fs_library_vtable_t **vtable, const char *fs_type,
202 apr_pool_t *pool)
204 const struct fs_type_defn *fst;
206 for (fst = fs_modules; fst->fs_type; fst++)
208 if (strcmp(fs_type, fst->fs_type) == 0)
209 return get_library_vtable_direct(vtable, fst, pool);
212 return svn_error_createf(SVN_ERR_FS_UNKNOWN_FS_TYPE, NULL,
213 _("Unknown FS type '%s'"), fs_type);
216 svn_error_t *
217 svn_fs_type(const char **fs_type, const char *path, apr_pool_t *pool)
219 const char *filename;
220 char buf[128];
221 svn_error_t *err;
222 apr_file_t *file;
223 apr_size_t len;
225 /* Read the fsap-name file to get the FSAP name, or assume the (old)
226 default. */
227 filename = svn_path_join(path, FS_TYPE_FILENAME, pool);
228 err = svn_io_file_open(&file, filename, APR_READ|APR_BUFFERED, 0, pool);
229 if (err && APR_STATUS_IS_ENOENT(err->apr_err))
231 svn_error_clear(err);
232 *fs_type = apr_pstrdup(pool, SVN_FS_TYPE_BDB);
233 return SVN_NO_ERROR;
235 else if (err)
236 return err;
238 len = sizeof(buf);
239 SVN_ERR(svn_io_read_length_line(file, buf, &len, pool));
240 SVN_ERR(svn_io_file_close(file, pool));
241 *fs_type = apr_pstrdup(pool, buf);
243 return SVN_NO_ERROR;
246 /* Fetch the library vtable for an existing FS. */
247 static svn_error_t *
248 fs_library_vtable(fs_library_vtable_t **vtable, const char *path,
249 apr_pool_t *pool)
251 const char *fs_type;
253 SVN_ERR(svn_fs_type(&fs_type, path, pool));
255 /* Fetch the library vtable by name, now that we've chosen one. */
256 return get_library_vtable(vtable, fs_type, pool);
259 static svn_error_t *
260 write_fs_type(const char *path, const char *fs_type, apr_pool_t *pool)
262 const char *filename;
263 apr_file_t *file;
265 filename = svn_path_join(path, FS_TYPE_FILENAME, pool);
266 SVN_ERR(svn_io_file_open(&file, filename,
267 APR_WRITE|APR_CREATE|APR_TRUNCATE|APR_BUFFERED,
268 APR_OS_DEFAULT, pool));
269 SVN_ERR(svn_io_file_write_full(file, fs_type, strlen(fs_type), NULL,
270 pool));
271 SVN_ERR(svn_io_file_write_full(file, "\n", 1, NULL, pool));
272 SVN_ERR(svn_io_file_close(file, pool));
273 return SVN_NO_ERROR;
277 /* --- Functions for operating on filesystems by pathname --- */
279 static apr_status_t uninit(void *data)
281 common_pool = NULL;
282 #if APR_HAS_THREADS
283 common_pool_lock = NULL;
284 #endif
285 return APR_SUCCESS;
288 svn_error_t *
289 svn_fs_initialize(apr_pool_t *pool)
291 #if APR_HAS_THREADS
292 apr_status_t status;
293 #endif
295 /* Protect against multiple calls. */
296 if (common_pool)
297 return SVN_NO_ERROR;
299 common_pool = svn_pool_create(pool);
300 #if APR_HAS_THREADS
301 status = apr_thread_mutex_create(&common_pool_lock,
302 APR_THREAD_MUTEX_DEFAULT, common_pool);
303 if (status)
304 return svn_error_wrap_apr(status, _("Can't allocate FS mutex"));
305 #endif
307 /* ### This won't work if POOL is NULL and libsvn_fs is loaded as a DSO
308 ### (via libsvn_ra_local say) since the global common_pool will live
309 ### longer than the DSO, which gets unloaded when the pool used to
310 ### load it is cleared, and so when the handler runs it will refer to
311 ### a function that no longer exists. libsvn_ra_local attempts to
312 ### work around this by explicitly calling svn_fs_initialize. */
313 apr_pool_cleanup_register(common_pool, NULL, uninit, apr_pool_cleanup_null);
314 return SVN_NO_ERROR;
317 /* A default warning handling function. */
318 static void
319 default_warning_func(void *baton, svn_error_t *err)
321 /* The one unforgiveable sin is to fail silently. Dumping to stderr
322 or /dev/tty is not acceptable default behavior for server
323 processes, since those may both be equivalent to /dev/null. */
324 abort();
327 /* This API is publicly deprecated, but we continue to use it
328 internally to properly allocate svn_fs_t structures. */
329 svn_fs_t *
330 svn_fs_new(apr_hash_t *fs_config, apr_pool_t *pool)
332 svn_fs_t *fs = apr_palloc(pool, sizeof(*fs));
333 fs->pool = pool;
334 fs->path = NULL;
335 fs->warning = default_warning_func;
336 fs->warning_baton = NULL;
337 fs->config = fs_config;
338 fs->access_ctx = NULL;
339 fs->vtable = NULL;
340 fs->fsap_data = NULL;
341 return fs;
344 void
345 svn_fs_set_warning_func(svn_fs_t *fs, svn_fs_warning_callback_t warning,
346 void *warning_baton)
348 fs->warning = warning;
349 fs->warning_baton = warning_baton;
352 svn_error_t *
353 svn_fs_create(svn_fs_t **fs_p, const char *path, apr_hash_t *fs_config,
354 apr_pool_t *pool)
356 svn_error_t *err;
357 svn_error_t *err2;
358 fs_library_vtable_t *vtable;
359 const char *fs_type = NULL;
361 if (fs_config)
362 fs_type = apr_hash_get(fs_config, SVN_FS_CONFIG_FS_TYPE,
363 APR_HASH_KEY_STRING);
364 if (fs_type == NULL)
365 fs_type = DEFAULT_FS_TYPE;
366 SVN_ERR(get_library_vtable(&vtable, fs_type, pool));
368 /* Create the FS directory and write out the fsap-name file. */
369 SVN_ERR(svn_io_dir_make_sgid(path, APR_OS_DEFAULT, pool));
370 SVN_ERR(write_fs_type(path, fs_type, pool));
372 /* Perform the actual creation. */
373 *fs_p = svn_fs_new(fs_config, pool);
374 SVN_ERR(acquire_fs_mutex());
375 err = vtable->create(*fs_p, path, pool, common_pool);
376 err2 = release_fs_mutex();
377 if (err)
379 svn_error_clear(err2);
380 return err;
382 return err2;
385 svn_error_t *
386 svn_fs_open(svn_fs_t **fs_p, const char *path, apr_hash_t *fs_config,
387 apr_pool_t *pool)
389 svn_error_t *err;
390 svn_error_t *err2;
391 fs_library_vtable_t *vtable;
393 SVN_ERR(fs_library_vtable(&vtable, path, pool));
394 *fs_p = svn_fs_new(fs_config, pool);
395 SVN_ERR(acquire_fs_mutex());
396 err = vtable->open_fs(*fs_p, path, pool, common_pool);
397 err2 = release_fs_mutex();
398 if (err)
400 svn_error_clear(err2);
401 return err;
403 return err2;
406 svn_error_t *
407 svn_fs_upgrade(const char *path, apr_pool_t *pool)
409 svn_error_t *err;
410 svn_error_t *err2;
411 fs_library_vtable_t *vtable;
412 svn_fs_t *fs;
414 SVN_ERR(fs_library_vtable(&vtable, path, pool));
415 fs = svn_fs_new(NULL, pool);
416 SVN_ERR(acquire_fs_mutex());
417 err = vtable->upgrade_fs(fs, path, pool, common_pool);
418 err2 = release_fs_mutex();
419 if (err)
421 svn_error_clear(err2);
422 return err;
424 return err2;
427 const char *
428 svn_fs_path(svn_fs_t *fs, apr_pool_t *pool)
430 return apr_pstrdup(pool, fs->path);
433 svn_error_t *
434 svn_fs_delete_fs(const char *path, apr_pool_t *pool)
436 fs_library_vtable_t *vtable;
438 SVN_ERR(fs_library_vtable(&vtable, path, pool));
439 return vtable->delete_fs(path, pool);
442 svn_error_t *
443 svn_fs_hotcopy(const char *src_path, const char *dest_path,
444 svn_boolean_t clean, apr_pool_t *pool)
446 fs_library_vtable_t *vtable;
447 const char *fs_type;
449 SVN_ERR(svn_fs_type(&fs_type, src_path, pool));
450 SVN_ERR(get_library_vtable(&vtable, fs_type, pool));
451 SVN_ERR(vtable->hotcopy(src_path, dest_path, clean, pool));
452 SVN_ERR(write_fs_type(dest_path, fs_type, pool));
454 return SVN_NO_ERROR;
457 svn_error_t *
458 svn_fs_recover(const char *path,
459 svn_cancel_func_t cancel_func, void *cancel_baton,
460 apr_pool_t *pool)
462 svn_error_t *err;
463 svn_error_t *err2;
464 fs_library_vtable_t *vtable;
465 svn_fs_t *fs;
467 SVN_ERR(fs_library_vtable(&vtable, path, pool));
468 fs = svn_fs_new(NULL, pool);
469 SVN_ERR(acquire_fs_mutex());
470 err = vtable->open_fs_for_recovery(fs, path, pool, common_pool);
471 err2 = release_fs_mutex();
472 if (err)
474 svn_error_clear(err2);
475 return err;
477 if (! err2)
478 err2 = vtable->recover(fs, cancel_func, cancel_baton, pool);
479 return err2;
483 /* --- Berkeley-specific functions --- */
485 svn_error_t *
486 svn_fs_create_berkeley(svn_fs_t *fs, const char *path)
488 svn_error_t *err;
489 svn_error_t *err2;
490 fs_library_vtable_t *vtable;
492 SVN_ERR(get_library_vtable(&vtable, SVN_FS_TYPE_BDB, fs->pool));
494 /* Create the FS directory and write out the fsap-name file. */
495 SVN_ERR(svn_io_dir_make_sgid(path, APR_OS_DEFAULT, fs->pool));
496 SVN_ERR(write_fs_type(path, SVN_FS_TYPE_BDB, fs->pool));
498 /* Perform the actual creation. */
499 SVN_ERR(acquire_fs_mutex());
500 err = vtable->create(fs, path, fs->pool, common_pool);
501 err2 = release_fs_mutex();
502 if (err)
504 svn_error_clear(err2);
505 return err;
507 return err2;
510 svn_error_t *
511 svn_fs_open_berkeley(svn_fs_t *fs, const char *path)
513 svn_error_t *err;
514 svn_error_t *err2;
515 fs_library_vtable_t *vtable;
517 SVN_ERR(fs_library_vtable(&vtable, path, fs->pool));
518 SVN_ERR(acquire_fs_mutex());
519 err = vtable->open_fs(fs, path, fs->pool, common_pool);
520 err2 = release_fs_mutex();
521 if (err)
523 svn_error_clear(err2);
524 return err;
526 return err2;
529 const char *
530 svn_fs_berkeley_path(svn_fs_t *fs, apr_pool_t *pool)
532 return svn_fs_path(fs, pool);
535 svn_error_t *
536 svn_fs_delete_berkeley(const char *path, apr_pool_t *pool)
538 return svn_fs_delete_fs(path, pool);
541 svn_error_t *
542 svn_fs_hotcopy_berkeley(const char *src_path, const char *dest_path,
543 svn_boolean_t clean_logs, apr_pool_t *pool)
545 return svn_fs_hotcopy(src_path, dest_path, clean_logs, pool);
548 svn_error_t *
549 svn_fs_berkeley_recover(const char *path, apr_pool_t *pool)
551 return svn_fs_recover(path, NULL, NULL, pool);
554 svn_error_t *
555 svn_fs_set_berkeley_errcall(svn_fs_t *fs,
556 void (*handler)(const char *errpfx, char *msg))
558 return fs->vtable->bdb_set_errcall(fs, handler);
561 svn_error_t *
562 svn_fs_berkeley_logfiles(apr_array_header_t **logfiles,
563 const char *path,
564 svn_boolean_t only_unused,
565 apr_pool_t *pool)
567 fs_library_vtable_t *vtable;
569 SVN_ERR(fs_library_vtable(&vtable, path, pool));
570 return vtable->bdb_logfiles(logfiles, path, only_unused, pool);
574 /* --- Transaction functions --- */
576 svn_error_t *
577 svn_fs_begin_txn2(svn_fs_txn_t **txn_p, svn_fs_t *fs, svn_revnum_t rev,
578 apr_uint32_t flags, apr_pool_t *pool)
580 return fs->vtable->begin_txn(txn_p, fs, rev, flags, pool);
584 svn_error_t *
585 svn_fs_begin_txn(svn_fs_txn_t **txn_p, svn_fs_t *fs, svn_revnum_t rev,
586 apr_pool_t *pool)
588 return fs->vtable->begin_txn(txn_p, fs, rev, 0, pool);
591 svn_error_t *
592 svn_fs_commit_txn(const char **conflict_p, svn_revnum_t *new_rev,
593 svn_fs_txn_t *txn, apr_pool_t *pool)
595 return txn->vtable->commit(conflict_p, new_rev, txn, pool);
598 svn_error_t *
599 svn_fs_abort_txn(svn_fs_txn_t *txn, apr_pool_t *pool)
601 return txn->vtable->abort(txn, pool);
604 svn_error_t *
605 svn_fs_purge_txn(svn_fs_t *fs, const char *txn_id, apr_pool_t *pool)
607 return fs->vtable->purge_txn(fs, txn_id, pool);
610 svn_error_t *
611 svn_fs_txn_name(const char **name_p, svn_fs_txn_t *txn, apr_pool_t *pool)
613 *name_p = apr_pstrdup(pool, txn->id);
614 return SVN_NO_ERROR;
617 svn_revnum_t
618 svn_fs_txn_base_revision(svn_fs_txn_t *txn)
620 return txn->base_rev;
623 svn_error_t *
624 svn_fs_open_txn(svn_fs_txn_t **txn, svn_fs_t *fs, const char *name,
625 apr_pool_t *pool)
627 return fs->vtable->open_txn(txn, fs, name, pool);
630 svn_error_t *
631 svn_fs_list_transactions(apr_array_header_t **names_p, svn_fs_t *fs,
632 apr_pool_t *pool)
634 return fs->vtable->list_transactions(names_p, fs, pool);
637 svn_error_t *
638 svn_fs_txn_prop(svn_string_t **value_p, svn_fs_txn_t *txn,
639 const char *propname, apr_pool_t *pool)
641 return txn->vtable->get_prop(value_p, txn, propname, pool);
644 svn_error_t *
645 svn_fs_txn_proplist(apr_hash_t **table_p, svn_fs_txn_t *txn, apr_pool_t *pool)
647 return txn->vtable->get_proplist(table_p, txn, pool);
650 svn_error_t *
651 svn_fs_change_txn_prop(svn_fs_txn_t *txn, const char *name,
652 const svn_string_t *value, apr_pool_t *pool)
654 return txn->vtable->change_prop(txn, name, value, pool);
657 svn_error_t *
658 svn_fs_change_txn_props(svn_fs_txn_t *txn, apr_array_header_t *props,
659 apr_pool_t *pool)
661 return txn->vtable->change_props(txn, props, pool);
665 /* --- Root functions --- */
667 svn_error_t *
668 svn_fs_revision_root(svn_fs_root_t **root_p, svn_fs_t *fs, svn_revnum_t rev,
669 apr_pool_t *pool)
671 return fs->vtable->revision_root(root_p, fs, rev, pool);
674 svn_error_t *
675 svn_fs_txn_root(svn_fs_root_t **root_p, svn_fs_txn_t *txn, apr_pool_t *pool)
677 return txn->vtable->root(root_p, txn, pool);
680 void
681 svn_fs_close_root(svn_fs_root_t *root)
683 svn_pool_destroy(root->pool);
686 svn_fs_t *
687 svn_fs_root_fs(svn_fs_root_t *root)
689 return root->fs;
692 svn_boolean_t
693 svn_fs_is_txn_root(svn_fs_root_t *root)
695 return root->is_txn_root;
698 svn_boolean_t
699 svn_fs_is_revision_root(svn_fs_root_t *root)
701 return !root->is_txn_root;
704 const char *
705 svn_fs_txn_root_name(svn_fs_root_t *root, apr_pool_t *pool)
707 return root->is_txn_root ? apr_pstrdup(pool, root->txn) : NULL;
710 svn_revnum_t
711 svn_fs_txn_root_base_revision(svn_fs_root_t *root)
713 return root->is_txn_root ? root->rev : SVN_INVALID_REVNUM;
716 svn_revnum_t
717 svn_fs_revision_root_revision(svn_fs_root_t *root)
719 return root->is_txn_root ? SVN_INVALID_REVNUM : root->rev;
722 svn_error_t *
723 svn_fs_paths_changed(apr_hash_t **changed_paths_p, svn_fs_root_t *root,
724 apr_pool_t *pool)
726 return root->vtable->paths_changed(changed_paths_p, root, pool);
729 svn_error_t *
730 svn_fs_check_path(svn_node_kind_t *kind_p, svn_fs_root_t *root,
731 const char *path, apr_pool_t *pool)
733 return root->vtable->check_path(kind_p, root, path, pool);
736 svn_error_t *
737 svn_fs_node_history(svn_fs_history_t **history_p, svn_fs_root_t *root,
738 const char *path, apr_pool_t *pool)
740 return root->vtable->node_history(history_p, root, path, pool);
743 svn_error_t *
744 svn_fs_is_dir(svn_boolean_t *is_dir, svn_fs_root_t *root, const char *path,
745 apr_pool_t *pool)
747 svn_node_kind_t kind;
749 SVN_ERR(root->vtable->check_path(&kind, root, path, pool));
750 *is_dir = (kind == svn_node_dir);
751 return SVN_NO_ERROR;
754 svn_error_t *
755 svn_fs_is_file(svn_boolean_t *is_file, svn_fs_root_t *root, const char *path,
756 apr_pool_t *pool)
758 svn_node_kind_t kind;
760 SVN_ERR(root->vtable->check_path(&kind, root, path, pool));
761 *is_file = (kind == svn_node_file);
762 return SVN_NO_ERROR;
765 svn_error_t *
766 svn_fs_node_id(const svn_fs_id_t **id_p, svn_fs_root_t *root,
767 const char *path, apr_pool_t *pool)
769 return root->vtable->node_id(id_p, root, path, pool);
772 svn_error_t *
773 svn_fs_node_created_rev(svn_revnum_t *revision, svn_fs_root_t *root,
774 const char *path, apr_pool_t *pool)
776 return root->vtable->node_created_rev(revision, root, path, pool);
779 svn_error_t *
780 svn_fs_node_origin_rev(svn_revnum_t *revision, svn_fs_root_t *root,
781 const char *path, apr_pool_t *pool)
783 return root->vtable->node_origin_rev(revision, root, path, pool);
786 svn_error_t *
787 svn_fs_node_created_path(const char **created_path, svn_fs_root_t *root,
788 const char *path, apr_pool_t *pool)
790 return root->vtable->node_created_path(created_path, root, path, pool);
793 svn_error_t *
794 svn_fs_node_prop(svn_string_t **value_p, svn_fs_root_t *root,
795 const char *path, const char *propname, apr_pool_t *pool)
797 return root->vtable->node_prop(value_p, root, path, propname, pool);
800 svn_error_t *
801 svn_fs_node_proplist(apr_hash_t **table_p, svn_fs_root_t *root,
802 const char *path, apr_pool_t *pool)
804 return root->vtable->node_proplist(table_p, root, path, pool);
807 svn_error_t *
808 svn_fs_change_node_prop(svn_fs_root_t *root, const char *path,
809 const char *name, const svn_string_t *value,
810 apr_pool_t *pool)
812 return root->vtable->change_node_prop(root, path, name, value, pool);
815 svn_error_t *
816 svn_fs_props_changed(svn_boolean_t *changed_p, svn_fs_root_t *root1,
817 const char *path1, svn_fs_root_t *root2,
818 const char *path2, apr_pool_t *pool)
820 return root1->vtable->props_changed(changed_p, root1, path1, root2, path2,
821 pool);
824 svn_error_t *
825 svn_fs_copied_from(svn_revnum_t *rev_p, const char **path_p,
826 svn_fs_root_t *root, const char *path, apr_pool_t *pool)
828 return root->vtable->copied_from(rev_p, path_p, root, path, pool);
831 svn_error_t *
832 svn_fs_closest_copy(svn_fs_root_t **root_p, const char **path_p,
833 svn_fs_root_t *root, const char *path, apr_pool_t *pool)
835 return root->vtable->closest_copy(root_p, path_p, root, path, pool);
838 svn_error_t *
839 svn_fs_get_mergeinfo(svn_mergeinfo_catalog_t *catalog,
840 svn_fs_root_t *root,
841 const apr_array_header_t *paths,
842 svn_mergeinfo_inheritance_t inherit,
843 svn_boolean_t include_descendants,
844 apr_pool_t *pool)
846 return root->vtable->get_mergeinfo(catalog, root, paths, inherit,
847 include_descendants, pool);
850 svn_error_t *
851 svn_fs_merge(const char **conflict_p, svn_fs_root_t *source_root,
852 const char *source_path, svn_fs_root_t *target_root,
853 const char *target_path, svn_fs_root_t *ancestor_root,
854 const char *ancestor_path, apr_pool_t *pool)
856 return target_root->vtable->merge(conflict_p, source_root, source_path,
857 target_root, target_path, ancestor_root,
858 ancestor_path, pool);
861 svn_error_t *
862 svn_fs_dir_entries(apr_hash_t **entries_p, svn_fs_root_t *root,
863 const char *path, apr_pool_t *pool)
865 return root->vtable->dir_entries(entries_p, root, path, pool);
868 svn_error_t *
869 svn_fs_make_dir(svn_fs_root_t *root, const char *path, apr_pool_t *pool)
871 SVN_ERR(svn_path_check_valid(path, pool));
872 return root->vtable->make_dir(root, path, pool);
875 svn_error_t *
876 svn_fs_delete(svn_fs_root_t *root, const char *path, apr_pool_t *pool)
878 return root->vtable->delete_node(root, path, pool);
881 svn_error_t *
882 svn_fs_copy(svn_fs_root_t *from_root, const char *from_path,
883 svn_fs_root_t *to_root, const char *to_path, apr_pool_t *pool)
885 SVN_ERR(svn_path_check_valid(to_path, pool));
886 return to_root->vtable->copy(from_root, from_path, to_root, to_path, pool);
889 svn_error_t *
890 svn_fs_revision_link(svn_fs_root_t *from_root, svn_fs_root_t *to_root,
891 const char *path, apr_pool_t *pool)
893 return to_root->vtable->revision_link(from_root, to_root, path, pool);
896 svn_error_t *
897 svn_fs_file_length(svn_filesize_t *length_p, svn_fs_root_t *root,
898 const char *path, apr_pool_t *pool)
900 return root->vtable->file_length(length_p, root, path, pool);
903 svn_error_t *
904 svn_fs_file_md5_checksum(unsigned char digest[], svn_fs_root_t *root,
905 const char *path, apr_pool_t *pool)
907 return root->vtable->file_md5_checksum(digest, root, path, pool);
910 svn_error_t *
911 svn_fs_file_contents(svn_stream_t **contents, svn_fs_root_t *root,
912 const char *path, apr_pool_t *pool)
914 return root->vtable->file_contents(contents, root, path, pool);
917 svn_error_t *
918 svn_fs_make_file(svn_fs_root_t *root, const char *path, apr_pool_t *pool)
920 SVN_ERR(svn_path_check_valid(path, pool));
921 return root->vtable->make_file(root, path, pool);
924 svn_error_t *
925 svn_fs_apply_textdelta(svn_txdelta_window_handler_t *contents_p,
926 void **contents_baton_p, svn_fs_root_t *root,
927 const char *path, const char *base_checksum,
928 const char *result_checksum, apr_pool_t *pool)
930 return root->vtable->apply_textdelta(contents_p, contents_baton_p, root,
931 path, base_checksum, result_checksum,
932 pool);
935 svn_error_t *
936 svn_fs_apply_text(svn_stream_t **contents_p, svn_fs_root_t *root,
937 const char *path, const char *result_checksum,
938 apr_pool_t *pool)
940 return root->vtable->apply_text(contents_p, root, path, result_checksum,
941 pool);
944 svn_error_t *
945 svn_fs_contents_changed(svn_boolean_t *changed_p, svn_fs_root_t *root1,
946 const char *path1, svn_fs_root_t *root2,
947 const char *path2, apr_pool_t *pool)
949 return root1->vtable->contents_changed(changed_p, root1, path1, root2,
950 path2, pool);
953 svn_error_t *
954 svn_fs_youngest_rev(svn_revnum_t *youngest_p, svn_fs_t *fs, apr_pool_t *pool)
956 return fs->vtable->youngest_rev(youngest_p, fs, pool);
959 svn_error_t *
960 svn_fs_deltify_revision(svn_fs_t *fs, svn_revnum_t revision, apr_pool_t *pool)
962 return fs->vtable->deltify(fs, revision, pool);
965 svn_error_t *
966 svn_fs_revision_prop(svn_string_t **value_p, svn_fs_t *fs, svn_revnum_t rev,
967 const char *propname, apr_pool_t *pool)
969 return fs->vtable->revision_prop(value_p, fs, rev, propname, pool);
972 svn_error_t *
973 svn_fs_revision_proplist(apr_hash_t **table_p, svn_fs_t *fs, svn_revnum_t rev,
974 apr_pool_t *pool)
976 return fs->vtable->revision_proplist(table_p, fs, rev, pool);
979 svn_error_t *
980 svn_fs_change_rev_prop(svn_fs_t *fs, svn_revnum_t rev, const char *name,
981 const svn_string_t *value, apr_pool_t *pool)
983 return fs->vtable->change_rev_prop(fs, rev, name, value, pool);
986 svn_error_t *
987 svn_fs_get_file_delta_stream(svn_txdelta_stream_t **stream_p,
988 svn_fs_root_t *source_root,
989 const char *source_path,
990 svn_fs_root_t *target_root,
991 const char *target_path, apr_pool_t *pool)
993 return target_root->vtable->get_file_delta_stream(stream_p, source_root,
994 source_path, target_root,
995 target_path, pool);
998 svn_error_t *
999 svn_fs_get_uuid(svn_fs_t *fs, const char **uuid, apr_pool_t *pool)
1001 return fs->vtable->get_uuid(fs, uuid, pool);
1004 svn_error_t *
1005 svn_fs_set_uuid(svn_fs_t *fs, const char *uuid, apr_pool_t *pool)
1007 if (! uuid)
1009 uuid = svn_uuid_generate(pool);
1011 else
1013 apr_uuid_t parsed_uuid;
1014 apr_status_t apr_err = apr_uuid_parse(&parsed_uuid, uuid);
1015 if (apr_err)
1016 return svn_error_createf(SVN_ERR_BAD_UUID, NULL,
1017 _("Malformed UUID '%s'"), uuid);
1019 return fs->vtable->set_uuid(fs, uuid, pool);
1022 svn_error_t *
1023 svn_fs_lock(svn_lock_t **lock, svn_fs_t *fs, const char *path,
1024 const char *token, const char *comment,
1025 svn_boolean_t is_dav_comment, apr_time_t expiration_date,
1026 svn_revnum_t current_rev, svn_boolean_t steal_lock,
1027 apr_pool_t *pool)
1029 /* Enforce that the comment be xml-escapable. */
1030 if (comment)
1032 if (! svn_xml_is_xml_safe(comment, strlen(comment)))
1033 return svn_error_create
1034 (SVN_ERR_XML_UNESCAPABLE_DATA, NULL,
1035 _("Lock comment contains illegal characters"));
1038 if (expiration_date < 0)
1039 return svn_error_create
1040 (SVN_ERR_INCORRECT_PARAMS, NULL,
1041 _("Negative expiration date passed to svn_fs_lock"));
1043 return fs->vtable->lock(lock, fs, path, token, comment, is_dav_comment,
1044 expiration_date, current_rev, steal_lock, pool);
1047 svn_error_t *
1048 svn_fs_generate_lock_token(const char **token, svn_fs_t *fs, apr_pool_t *pool)
1050 return fs->vtable->generate_lock_token(token, fs, pool);
1053 svn_error_t *
1054 svn_fs_unlock(svn_fs_t *fs, const char *path, const char *token,
1055 svn_boolean_t break_lock, apr_pool_t *pool)
1057 return fs->vtable->unlock(fs, path, token, break_lock, pool);
1060 svn_error_t *
1061 svn_fs_get_lock(svn_lock_t **lock, svn_fs_t *fs, const char *path,
1062 apr_pool_t *pool)
1064 return fs->vtable->get_lock(lock, fs, path, pool);
1067 svn_error_t *
1068 svn_fs_get_locks(svn_fs_t *fs, const char *path,
1069 svn_fs_get_locks_callback_t get_locks_func,
1070 void *get_locks_baton,
1071 apr_pool_t *pool)
1073 return fs->vtable->get_locks(fs, path, get_locks_func,
1074 get_locks_baton, pool);
1079 /* --- History functions --- */
1081 svn_error_t *
1082 svn_fs_history_prev(svn_fs_history_t **prev_history_p,
1083 svn_fs_history_t *history, svn_boolean_t cross_copies,
1084 apr_pool_t *pool)
1086 return history->vtable->prev(prev_history_p, history, cross_copies, pool);
1089 svn_error_t *
1090 svn_fs_history_location(const char **path, svn_revnum_t *revision,
1091 svn_fs_history_t *history, apr_pool_t *pool)
1093 return history->vtable->location(path, revision, history, pool);
1097 /* --- Node-ID functions --- */
1099 svn_fs_id_t *
1100 svn_fs_parse_id(const char *data, apr_size_t len, apr_pool_t *pool)
1102 fs_library_vtable_t *vtable;
1103 svn_error_t *err;
1105 err = get_library_vtable(&vtable, SVN_FS_TYPE_BDB, pool);
1106 if (err)
1108 svn_error_clear(err);
1109 return NULL;
1111 return vtable->parse_id(data, len, pool);
1114 svn_string_t *
1115 svn_fs_unparse_id(const svn_fs_id_t *id, apr_pool_t *pool)
1117 return id->vtable->unparse(id, pool);
1120 svn_boolean_t
1121 svn_fs_check_related(const svn_fs_id_t *a, const svn_fs_id_t *b)
1123 return (a->vtable->compare(a, b) != -1);
1127 svn_fs_compare_ids(const svn_fs_id_t *a, const svn_fs_id_t *b)
1129 return a->vtable->compare(a, b);
1132 svn_error_t *
1133 svn_fs_print_modules(svn_stringbuf_t *output,
1134 apr_pool_t *pool)
1136 const struct fs_type_defn *defn;
1137 fs_library_vtable_t *vtable;
1138 apr_pool_t *iterpool = svn_pool_create(pool);
1140 for (defn = fs_modules; defn->fs_type != NULL; ++defn)
1142 char *line;
1143 svn_error_t *err;
1145 svn_pool_clear(iterpool);
1147 err = get_library_vtable_direct(&vtable, defn, iterpool);
1148 if (err)
1150 if (err->apr_err == SVN_ERR_FS_UNKNOWN_FS_TYPE)
1152 svn_error_clear(err);
1153 continue;
1155 else
1156 return err;
1159 line = apr_psprintf(iterpool, "* fs_%s : %s\n",
1160 defn->fsap_name, vtable->get_description());
1161 svn_stringbuf_appendcstr(output, line);
1164 svn_pool_destroy(iterpool);
1166 return SVN_NO_ERROR;
1170 /* Return the library version number. */
1171 const svn_version_t *
1172 svn_fs_version(void)
1174 SVN_VERSION_BODY;