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 * ====================================================================
23 #include <apr_thread_mutex.h>
26 #include "svn_types.h"
28 #include "svn_version.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"
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
;
50 static apr_thread_mutex_t
*common_pool_lock
;
54 /* --- Utility functions for the loader --- */
56 static const struct fs_type_defn
{
58 const char *fsap_name
;
59 fs_init_func_t initfunc
;
62 SVN_FS_TYPE_BDB
, "base",
63 #ifdef SVN_LIBSVN_FS_LINKS_FS_BASE
69 SVN_FS_TYPE_FSFS
, "fs",
70 #ifdef SVN_LIBSVN_FS_LINKS_FS_FS
79 load_module(fs_init_func_t
*initfunc
, const char *name
, apr_pool_t
*pool
)
85 apr_dso_handle_t
*dso
;
86 apr_dso_handle_sym_t symbol
;
91 libname
= apr_psprintf(pool
, "libsvn_fs_%s-%d.so.0",
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
98 SVN_ERR(svn_dso_load(&dso
, libname
));
102 /* find the initialization routine */
103 status
= apr_dso_sym(&symbol
, dso
, funcname
);
105 return svn_error_wrap_apr(status
, _("'%s' does not define '%s()'"),
108 *initfunc
= (fs_init_func_t
) symbol
;
110 #endif /* APR_HAS_DSO */
116 acquire_fs_mutex(void)
120 status
= apr_thread_mutex_lock(common_pool_lock
);
122 return svn_error_wrap_apr(status
, _("Can't grab FS mutex"));
128 release_fs_mutex(void)
132 status
= apr_thread_mutex_unlock(common_pool_lock
);
134 return svn_error_wrap_apr(status
, _("Can't ungrab FS mutex"));
139 /* Fetch a library vtable by a pointer into the library definitions array. */
141 get_library_vtable_direct(fs_library_vtable_t
**vtable
,
142 const struct fs_type_defn
*fst
,
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
;
151 SVN_ERR(load_module(&initfunc
, fst
->fsap_name
, pool
));
154 return svn_error_createf(SVN_ERR_FS_UNKNOWN_FS_TYPE
, NULL
,
155 _("Failed to load module for FS type '%s'"),
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. */
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();
179 svn_error_clear(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':"
190 " expected %d.%d.%d%s"),
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
);
199 /* Fetch a library vtable by FS type. */
201 get_library_vtable(fs_library_vtable_t
**vtable
, const char *fs_type
,
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
);
217 svn_fs_type(const char **fs_type
, const char *path
, apr_pool_t
*pool
)
219 const char *filename
;
225 /* Read the fsap-name file to get the FSAP name, or assume the (old)
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
);
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
);
246 /* Fetch the library vtable for an existing FS. */
248 fs_library_vtable(fs_library_vtable_t
**vtable
, const char *path
,
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
);
260 write_fs_type(const char *path
, const char *fs_type
, apr_pool_t
*pool
)
262 const char *filename
;
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
,
271 SVN_ERR(svn_io_file_write_full(file
, "\n", 1, NULL
, pool
));
272 SVN_ERR(svn_io_file_close(file
, pool
));
277 /* --- Functions for operating on filesystems by pathname --- */
279 static apr_status_t
uninit(void *data
)
283 common_pool_lock
= NULL
;
289 svn_fs_initialize(apr_pool_t
*pool
)
295 /* Protect against multiple calls. */
299 common_pool
= svn_pool_create(pool
);
301 status
= apr_thread_mutex_create(&common_pool_lock
,
302 APR_THREAD_MUTEX_DEFAULT
, common_pool
);
304 return svn_error_wrap_apr(status
, _("Can't allocate FS mutex"));
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
);
317 /* A default warning handling function. */
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. */
327 /* This API is publicly deprecated, but we continue to use it
328 internally to properly allocate svn_fs_t structures. */
330 svn_fs_new(apr_hash_t
*fs_config
, apr_pool_t
*pool
)
332 svn_fs_t
*fs
= apr_palloc(pool
, sizeof(*fs
));
335 fs
->warning
= default_warning_func
;
336 fs
->warning_baton
= NULL
;
337 fs
->config
= fs_config
;
338 fs
->access_ctx
= NULL
;
340 fs
->fsap_data
= NULL
;
345 svn_fs_set_warning_func(svn_fs_t
*fs
, svn_fs_warning_callback_t warning
,
348 fs
->warning
= warning
;
349 fs
->warning_baton
= warning_baton
;
353 svn_fs_create(svn_fs_t
**fs_p
, const char *path
, apr_hash_t
*fs_config
,
358 fs_library_vtable_t
*vtable
;
359 const char *fs_type
= NULL
;
362 fs_type
= apr_hash_get(fs_config
, SVN_FS_CONFIG_FS_TYPE
,
363 APR_HASH_KEY_STRING
);
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();
379 svn_error_clear(err2
);
386 svn_fs_open(svn_fs_t
**fs_p
, const char *path
, apr_hash_t
*fs_config
,
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();
400 svn_error_clear(err2
);
407 svn_fs_upgrade(const char *path
, apr_pool_t
*pool
)
411 fs_library_vtable_t
*vtable
;
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();
421 svn_error_clear(err2
);
428 svn_fs_path(svn_fs_t
*fs
, apr_pool_t
*pool
)
430 return apr_pstrdup(pool
, fs
->path
);
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
);
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
;
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
));
458 svn_fs_recover(const char *path
,
459 svn_cancel_func_t cancel_func
, void *cancel_baton
,
464 fs_library_vtable_t
*vtable
;
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();
474 svn_error_clear(err2
);
478 err2
= vtable
->recover(fs
, cancel_func
, cancel_baton
, pool
);
483 /* --- Berkeley-specific functions --- */
486 svn_fs_create_berkeley(svn_fs_t
*fs
, const char *path
)
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();
504 svn_error_clear(err2
);
511 svn_fs_open_berkeley(svn_fs_t
*fs
, const char *path
)
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();
523 svn_error_clear(err2
);
530 svn_fs_berkeley_path(svn_fs_t
*fs
, apr_pool_t
*pool
)
532 return svn_fs_path(fs
, pool
);
536 svn_fs_delete_berkeley(const char *path
, apr_pool_t
*pool
)
538 return svn_fs_delete_fs(path
, pool
);
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
);
549 svn_fs_berkeley_recover(const char *path
, apr_pool_t
*pool
)
551 return svn_fs_recover(path
, NULL
, NULL
, pool
);
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
);
562 svn_fs_berkeley_logfiles(apr_array_header_t
**logfiles
,
564 svn_boolean_t only_unused
,
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 --- */
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
);
585 svn_fs_begin_txn(svn_fs_txn_t
**txn_p
, svn_fs_t
*fs
, svn_revnum_t rev
,
588 return fs
->vtable
->begin_txn(txn_p
, fs
, rev
, 0, pool
);
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
);
599 svn_fs_abort_txn(svn_fs_txn_t
*txn
, apr_pool_t
*pool
)
601 return txn
->vtable
->abort(txn
, pool
);
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
);
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
);
618 svn_fs_txn_base_revision(svn_fs_txn_t
*txn
)
620 return txn
->base_rev
;
624 svn_fs_open_txn(svn_fs_txn_t
**txn
, svn_fs_t
*fs
, const char *name
,
627 return fs
->vtable
->open_txn(txn
, fs
, name
, pool
);
631 svn_fs_list_transactions(apr_array_header_t
**names_p
, svn_fs_t
*fs
,
634 return fs
->vtable
->list_transactions(names_p
, fs
, pool
);
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
);
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
);
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
);
658 svn_fs_change_txn_props(svn_fs_txn_t
*txn
, apr_array_header_t
*props
,
661 return txn
->vtable
->change_props(txn
, props
, pool
);
665 /* --- Root functions --- */
668 svn_fs_revision_root(svn_fs_root_t
**root_p
, svn_fs_t
*fs
, svn_revnum_t rev
,
671 return fs
->vtable
->revision_root(root_p
, fs
, rev
, pool
);
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
);
681 svn_fs_close_root(svn_fs_root_t
*root
)
683 svn_pool_destroy(root
->pool
);
687 svn_fs_root_fs(svn_fs_root_t
*root
)
693 svn_fs_is_txn_root(svn_fs_root_t
*root
)
695 return root
->is_txn_root
;
699 svn_fs_is_revision_root(svn_fs_root_t
*root
)
701 return !root
->is_txn_root
;
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
;
711 svn_fs_txn_root_base_revision(svn_fs_root_t
*root
)
713 return root
->is_txn_root
? root
->rev
: SVN_INVALID_REVNUM
;
717 svn_fs_revision_root_revision(svn_fs_root_t
*root
)
719 return root
->is_txn_root
? SVN_INVALID_REVNUM
: root
->rev
;
723 svn_fs_paths_changed(apr_hash_t
**changed_paths_p
, svn_fs_root_t
*root
,
726 return root
->vtable
->paths_changed(changed_paths_p
, root
, pool
);
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
);
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
);
744 svn_fs_is_dir(svn_boolean_t
*is_dir
, svn_fs_root_t
*root
, const char *path
,
747 svn_node_kind_t kind
;
749 SVN_ERR(root
->vtable
->check_path(&kind
, root
, path
, pool
));
750 *is_dir
= (kind
== svn_node_dir
);
755 svn_fs_is_file(svn_boolean_t
*is_file
, svn_fs_root_t
*root
, const char *path
,
758 svn_node_kind_t kind
;
760 SVN_ERR(root
->vtable
->check_path(&kind
, root
, path
, pool
));
761 *is_file
= (kind
== svn_node_file
);
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
);
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
);
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
);
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
);
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
);
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
);
808 svn_fs_change_node_prop(svn_fs_root_t
*root
, const char *path
,
809 const char *name
, const svn_string_t
*value
,
812 return root
->vtable
->change_node_prop(root
, path
, name
, value
, pool
);
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
,
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
);
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
);
839 svn_fs_get_mergeinfo(svn_mergeinfo_catalog_t
*catalog
,
841 const apr_array_header_t
*paths
,
842 svn_mergeinfo_inheritance_t inherit
,
843 svn_boolean_t include_descendants
,
846 return root
->vtable
->get_mergeinfo(catalog
, root
, paths
, inherit
,
847 include_descendants
, pool
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
,
936 svn_fs_apply_text(svn_stream_t
**contents_p
, svn_fs_root_t
*root
,
937 const char *path
, const char *result_checksum
,
940 return root
->vtable
->apply_text(contents_p
, root
, path
, result_checksum
,
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
,
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
);
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
);
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
);
973 svn_fs_revision_proplist(apr_hash_t
**table_p
, svn_fs_t
*fs
, svn_revnum_t rev
,
976 return fs
->vtable
->revision_proplist(table_p
, fs
, rev
, pool
);
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
);
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
,
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
);
1005 svn_fs_set_uuid(svn_fs_t
*fs
, const char *uuid
, apr_pool_t
*pool
)
1009 uuid
= svn_uuid_generate(pool
);
1013 apr_uuid_t parsed_uuid
;
1014 apr_status_t apr_err
= apr_uuid_parse(&parsed_uuid
, uuid
);
1016 return svn_error_createf(SVN_ERR_BAD_UUID
, NULL
,
1017 _("Malformed UUID '%s'"), uuid
);
1019 return fs
->vtable
->set_uuid(fs
, uuid
, pool
);
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
,
1029 /* Enforce that the comment be xml-escapable. */
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
);
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
);
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
);
1061 svn_fs_get_lock(svn_lock_t
**lock
, svn_fs_t
*fs
, const char *path
,
1064 return fs
->vtable
->get_lock(lock
, fs
, path
, pool
);
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
,
1073 return fs
->vtable
->get_locks(fs
, path
, get_locks_func
,
1074 get_locks_baton
, pool
);
1079 /* --- History functions --- */
1082 svn_fs_history_prev(svn_fs_history_t
**prev_history_p
,
1083 svn_fs_history_t
*history
, svn_boolean_t cross_copies
,
1086 return history
->vtable
->prev(prev_history_p
, history
, cross_copies
, pool
);
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 --- */
1100 svn_fs_parse_id(const char *data
, apr_size_t len
, apr_pool_t
*pool
)
1102 fs_library_vtable_t
*vtable
;
1105 err
= get_library_vtable(&vtable
, SVN_FS_TYPE_BDB
, pool
);
1108 svn_error_clear(err
);
1111 return vtable
->parse_id(data
, len
, pool
);
1115 svn_fs_unparse_id(const svn_fs_id_t
*id
, apr_pool_t
*pool
)
1117 return id
->vtable
->unparse(id
, pool
);
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
);
1133 svn_fs_print_modules(svn_stringbuf_t
*output
,
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
)
1145 svn_pool_clear(iterpool
);
1147 err
= get_library_vtable_direct(&vtable
, defn
, iterpool
);
1150 if (err
->apr_err
== SVN_ERR_FS_UNKNOWN_FS_TYPE
)
1152 svn_error_clear(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)