summaryrefslogtreecommitdiff
path: root/subversion/libsvn_fs/fs-loader.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_fs/fs-loader.c')
-rw-r--r--subversion/libsvn_fs/fs-loader.c735
1 files changed, 572 insertions, 163 deletions
diff --git a/subversion/libsvn_fs/fs-loader.c b/subversion/libsvn_fs/fs-loader.c
index 336b84f..ba90554 100644
--- a/subversion/libsvn_fs/fs-loader.c
+++ b/subversion/libsvn_fs/fs-loader.c
@@ -24,12 +24,14 @@
#include <string.h>
#include <apr.h>
+#include <apr_atomic.h>
#include <apr_hash.h>
#include <apr_md5.h>
#include <apr_thread_mutex.h>
#include <apr_uuid.h>
#include <apr_strings.h>
+#include "svn_private_config.h"
#include "svn_hash.h"
#include "svn_ctype.h"
#include "svn_types.h"
@@ -40,8 +42,9 @@
#include "svn_xml.h"
#include "svn_pools.h"
#include "svn_string.h"
-#include "svn_private_config.h"
+#include "svn_sorts.h"
+#include "private/svn_atomic.h"
#include "private/svn_fs_private.h"
#include "private/svn_fs_util.h"
#include "private/svn_utf_private.h"
@@ -60,8 +63,9 @@
/* A pool common to all FS objects. See the documentation on the
open/create functions in fs-loader.h and for svn_fs_initialize(). */
-static apr_pool_t *common_pool;
-svn_mutex__t *common_pool_lock;
+static apr_pool_t *common_pool = NULL;
+static svn_mutex__t *common_pool_lock = NULL;
+static svn_atomic_t common_pool_initialized = FALSE;
/* --- Utility functions for the loader --- */
@@ -70,6 +74,7 @@ struct fs_type_defn {
const char *fs_type;
const char *fsap_name;
fs_init_func_t initfunc;
+ fs_library_vtable_t *vtable;
struct fs_type_defn *next;
};
@@ -81,10 +86,23 @@ static struct fs_type_defn base_defn =
#else
NULL,
#endif
+ NULL,
NULL /* End of static list: this needs to be reset to NULL if the
common_pool used when setting it has been cleared. */
};
+static struct fs_type_defn fsx_defn =
+ {
+ SVN_FS_TYPE_FSX, "x",
+#ifdef SVN_LIBSVN_FS_LINKS_FS_X
+ svn_fs_x__init,
+#else
+ NULL,
+#endif
+ NULL,
+ &base_defn
+ };
+
static struct fs_type_defn fsfs_defn =
{
SVN_FS_TYPE_FSFS, "fs",
@@ -93,7 +111,8 @@ static struct fs_type_defn fsfs_defn =
#else
NULL,
#endif
- &base_defn
+ NULL,
+ &fsx_defn
};
static struct fs_type_defn *fs_modules = &fsfs_defn;
@@ -148,13 +167,20 @@ load_module(fs_init_func_t *initfunc, const char *name, apr_pool_t *pool)
/* Fetch a library vtable by a pointer into the library definitions array. */
static svn_error_t *
get_library_vtable_direct(fs_library_vtable_t **vtable,
- const struct fs_type_defn *fst,
+ struct fs_type_defn *fst,
apr_pool_t *pool)
{
fs_init_func_t initfunc = NULL;
const svn_version_t *my_version = svn_fs_version();
const svn_version_t *fs_version;
+ /* most times, we get lucky */
+ *vtable = apr_atomic_casptr((volatile void **)&fst->vtable, NULL, NULL);
+ if (*vtable)
+ return SVN_NO_ERROR;
+
+ /* o.k. the first access needs to actually load the module, find the
+ vtable and check for version compatibility. */
initfunc = fst->initfunc;
if (! initfunc)
SVN_ERR(load_module(&initfunc, fst->fsap_name, pool));
@@ -172,8 +198,7 @@ get_library_vtable_direct(fs_library_vtable_t **vtable,
unloaded. This function makes a best effort by creating the
common pool as a child of the global pool; the window of failure
due to thread collision is small. */
- if (!common_pool)
- SVN_ERR(svn_fs_initialize(NULL));
+ SVN_ERR(svn_fs_initialize(NULL));
/* Invoke the FS module's initfunc function with the common
pool protected by a lock. */
@@ -191,6 +216,10 @@ get_library_vtable_direct(fs_library_vtable_t **vtable,
my_version->patch, my_version->tag,
fs_version->major, fs_version->minor,
fs_version->patch, fs_version->tag);
+
+ /* the vtable will not change. Remember it */
+ apr_atomic_casptr((volatile void **)&fst->vtable, *vtable, NULL);
+
return SVN_NO_ERROR;
}
@@ -211,31 +240,37 @@ get_or_allocate_third(struct fs_type_defn **fst,
(*fst)->fs_type = apr_pstrdup(common_pool, fs_type);
(*fst)->fsap_name = (*fst)->fs_type;
(*fst)->initfunc = NULL;
+ (*fst)->vtable = NULL;
(*fst)->next = NULL;
return SVN_NO_ERROR;
}
#endif
-/* Fetch a library vtable by FS type. */
+/* Fetch a library *VTABLE by FS_TYPE.
+ Use POOL for temporary allocations. */
static svn_error_t *
get_library_vtable(fs_library_vtable_t **vtable, const char *fs_type,
apr_pool_t *pool)
{
- struct fs_type_defn **fst = &fs_modules;
+ struct fs_type_defn **fst;
svn_boolean_t known = FALSE;
- /* There are two FS module definitions known at compile time. We
+ /* There are three FS module definitions known at compile time. We
want to check these without any locking overhead even when
dynamic third party modules are enabled. The third party modules
cannot be checked until the lock is held. */
- if (strcmp(fs_type, (*fst)->fs_type) == 0)
- known = TRUE;
- else
+ for (fst = &fs_modules; *fst; fst = &(*fst)->next)
{
- fst = &(*fst)->next;
if (strcmp(fs_type, (*fst)->fs_type) == 0)
- known = TRUE;
+ {
+ known = TRUE;
+ break;
+ }
+ else if (!(*fst)->next)
+ {
+ break;
+ }
}
#if defined(SVN_USE_DSO) && APR_HAS_DSO
@@ -254,8 +289,8 @@ get_library_vtable(fs_library_vtable_t **vtable, const char *fs_type,
if (!known)
{
fst = &(*fst)->next;
- if (!common_pool) /* Best-effort init, see get_library_vtable_direct. */
- SVN_ERR(svn_fs_initialize(NULL));
+ /* Best-effort init, see get_library_vtable_direct. */
+ SVN_ERR(svn_fs_initialize(NULL));
SVN_MUTEX__WITH_LOCK(common_pool_lock,
get_or_allocate_third(fst, fs_type));
known = TRUE;
@@ -320,7 +355,9 @@ fs_library_vtable(fs_library_vtable_t **vtable, const char *path,
SVN_ERR(svn_fs_type(&fs_type, path, pool));
/* Fetch the library vtable by name, now that we've chosen one. */
- return svn_error_trace(get_library_vtable(vtable, fs_type, pool));
+ SVN_ERR(get_library_vtable(vtable, fs_type, pool));
+
+ return SVN_NO_ERROR;
}
static svn_error_t *
@@ -345,16 +382,15 @@ write_fs_type(const char *path, const char *fs_type, apr_pool_t *pool)
static apr_status_t uninit(void *data)
{
common_pool = NULL;
+ common_pool_lock = NULL;
+ common_pool_initialized = 0;
+
return APR_SUCCESS;
}
-svn_error_t *
-svn_fs_initialize(apr_pool_t *pool)
+static svn_error_t *
+synchronized_initialize(void *baton, apr_pool_t *pool)
{
- /* Protect against multiple calls. */
- if (common_pool)
- return SVN_NO_ERROR;
-
common_pool = svn_pool_create(pool);
base_defn.next = NULL;
SVN_ERR(svn_mutex__init(&common_pool_lock, TRUE, common_pool));
@@ -369,19 +405,44 @@ svn_fs_initialize(apr_pool_t *pool)
return SVN_NO_ERROR;
}
+svn_error_t *
+svn_fs_initialize(apr_pool_t *pool)
+{
+#if defined(SVN_USE_DSO) && APR_HAS_DSO
+ /* Ensure that DSO subsystem is initialized early as possible if
+ we're going to use it. */
+ SVN_ERR(svn_dso_initialize2());
+#endif
+ /* Protect against multiple calls. */
+ return svn_error_trace(svn_atomic__init_once(&common_pool_initialized,
+ synchronized_initialize,
+ NULL, pool));
+}
+
/* A default warning handling function. */
static void
default_warning_func(void *baton, svn_error_t *err)
{
/* The one unforgiveable sin is to fail silently. Dumping to stderr
or /dev/tty is not acceptable default behavior for server
- processes, since those may both be equivalent to /dev/null. */
+ processes, since those may both be equivalent to /dev/null.
+
+ That said, be a good citizen and print something anyway, in case it goes
+ somewhere, and our caller hasn't overridden the abort() call.
+ */
+ if (svn_error_get_malfunction_handler()
+ == svn_error_abort_on_malfunction)
+ /* ### TODO: extend the malfunction API such that non-abort()ing consumers
+ ### also get the information on ERR. */
+ svn_handle_error2(err, stderr, FALSE /* fatal */, "svn: fs-loader: ");
SVN_ERR_MALFUNCTION_NO_RETURN();
}
svn_error_t *
svn_fs__path_valid(const char *path, apr_pool_t *pool)
{
+ char *c;
+
/* UTF-8 encoded string without NULs. */
if (! svn_utf__cstring_is_valid(path))
{
@@ -398,6 +459,18 @@ svn_fs__path_valid(const char *path, apr_pool_t *pool)
path);
}
+ /* Raise an error if PATH contains a newline because svn:mergeinfo and
+ friends can't handle them. Issue #4340 describes a similar problem
+ in the FSFS code itself.
+ */
+ c = strchr(path, '\n');
+ if (c)
+ {
+ return svn_error_createf(SVN_ERR_FS_PATH_SYNTAX, NULL,
+ _("Invalid control character '0x%02x' in path '%s'"),
+ (unsigned char)*c, svn_path_illegal_path_escape(path, pool));
+ }
+
/* That's good enough. */
return SVN_NO_ERROR;
}
@@ -451,42 +524,66 @@ svn_fs_create(svn_fs_t **fs_p, const char *path, apr_hash_t *fs_config,
/* Perform the actual creation. */
*fs_p = fs_new(fs_config, pool);
- SVN_MUTEX__WITH_LOCK(common_pool_lock,
- vtable->create(*fs_p, path, pool, common_pool));
- SVN_ERR(vtable->set_svn_fs_open(*fs_p, svn_fs_open));
+ SVN_ERR(vtable->create(*fs_p, path, common_pool_lock, pool, common_pool));
+ SVN_ERR(vtable->set_svn_fs_open(*fs_p, svn_fs_open2));
return SVN_NO_ERROR;
}
svn_error_t *
-svn_fs_open(svn_fs_t **fs_p, const char *path, apr_hash_t *fs_config,
- apr_pool_t *pool)
+svn_fs_open2(svn_fs_t **fs_p, const char *path, apr_hash_t *fs_config,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
fs_library_vtable_t *vtable;
- SVN_ERR(fs_library_vtable(&vtable, path, pool));
- *fs_p = fs_new(fs_config, pool);
- SVN_MUTEX__WITH_LOCK(common_pool_lock,
- vtable->open_fs(*fs_p, path, pool, common_pool));
- SVN_ERR(vtable->set_svn_fs_open(*fs_p, svn_fs_open));
+ SVN_ERR(fs_library_vtable(&vtable, path, scratch_pool));
+ *fs_p = fs_new(fs_config, result_pool);
+ SVN_ERR(vtable->open_fs(*fs_p, path, common_pool_lock, scratch_pool,
+ common_pool));
+ SVN_ERR(vtable->set_svn_fs_open(*fs_p, svn_fs_open2));
return SVN_NO_ERROR;
}
svn_error_t *
-svn_fs_upgrade(const char *path, apr_pool_t *pool)
+svn_fs_open(svn_fs_t **fs_p,
+ const char *path,
+ apr_hash_t *fs_config,
+ apr_pool_t *pool)
+{
+ return svn_fs_open2(fs_p, path, fs_config, pool, pool);
+}
+
+svn_error_t *
+svn_fs_upgrade2(const char *path,
+ svn_fs_upgrade_notify_t notify_func,
+ void *notify_baton,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool)
{
fs_library_vtable_t *vtable;
svn_fs_t *fs;
- SVN_ERR(fs_library_vtable(&vtable, path, pool));
- fs = fs_new(NULL, pool);
+ SVN_ERR(fs_library_vtable(&vtable, path, scratch_pool));
+ fs = fs_new(NULL, scratch_pool);
- SVN_MUTEX__WITH_LOCK(common_pool_lock,
- vtable->upgrade_fs(fs, path, pool, common_pool));
+ SVN_ERR(vtable->upgrade_fs(fs, path,
+ notify_func, notify_baton,
+ cancel_func, cancel_baton,
+ common_pool_lock,
+ scratch_pool, common_pool));
return SVN_NO_ERROR;
}
+/* A warning handling function that does not abort on errors,
+ but just lets them be returned normally. */
+static void
+verify_fs_warning_func(void *baton, svn_error_t *err)
+{
+}
+
svn_error_t *
svn_fs_verify(const char *path,
apr_hash_t *fs_config,
@@ -503,12 +600,13 @@ svn_fs_verify(const char *path,
SVN_ERR(fs_library_vtable(&vtable, path, pool));
fs = fs_new(fs_config, pool);
+ svn_fs_set_warning_func(fs, verify_fs_warning_func, NULL);
- SVN_MUTEX__WITH_LOCK(common_pool_lock,
- vtable->verify_fs(fs, path, start, end,
- notify_func, notify_baton,
- cancel_func, cancel_baton,
- pool, common_pool));
+ SVN_ERR(vtable->verify_fs(fs, path, start, end,
+ notify_func, notify_baton,
+ cancel_func, cancel_baton,
+ common_pool_lock,
+ pool, common_pool));
return SVN_NO_ERROR;
}
@@ -537,9 +635,12 @@ svn_fs_delete_fs(const char *path, apr_pool_t *pool)
}
svn_error_t *
-svn_fs_hotcopy2(const char *src_path, const char *dst_path,
+svn_fs_hotcopy3(const char *src_path, const char *dst_path,
svn_boolean_t clean, svn_boolean_t incremental,
- svn_cancel_func_t cancel_func, void *cancel_baton,
+ svn_fs_hotcopy_notify_t notify_func,
+ void *notify_baton,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
apr_pool_t *scratch_pool)
{
fs_library_vtable_t *vtable;
@@ -592,20 +693,13 @@ svn_fs_hotcopy2(const char *src_path, const char *dst_path,
}
SVN_ERR(vtable->hotcopy(src_fs, dst_fs, src_path, dst_path, clean,
- incremental, cancel_func, cancel_baton,
- scratch_pool));
+ incremental, notify_func, notify_baton,
+ cancel_func, cancel_baton, common_pool_lock,
+ scratch_pool, common_pool));
return svn_error_trace(write_fs_type(dst_path, src_fs_type, scratch_pool));
}
svn_error_t *
-svn_fs_hotcopy(const char *src_path, const char *dest_path,
- svn_boolean_t clean, apr_pool_t *pool)
-{
- return svn_error_trace(svn_fs_hotcopy2(src_path, dest_path, clean,
- FALSE, NULL, NULL, pool));
-}
-
-svn_error_t *
svn_fs_pack(const char *path,
svn_fs_pack_notify_t notify_func,
void *notify_baton,
@@ -619,10 +713,9 @@ svn_fs_pack(const char *path,
SVN_ERR(fs_library_vtable(&vtable, path, pool));
fs = fs_new(NULL, pool);
- SVN_MUTEX__WITH_LOCK(common_pool_lock,
- vtable->pack_fs(fs, path, notify_func, notify_baton,
- cancel_func, cancel_baton, pool,
- common_pool));
+ SVN_ERR(vtable->pack_fs(fs, path, notify_func, notify_baton,
+ cancel_func, cancel_baton, common_pool_lock,
+ pool, common_pool));
return SVN_NO_ERROR;
}
@@ -637,9 +730,8 @@ svn_fs_recover(const char *path,
SVN_ERR(fs_library_vtable(&vtable, path, pool));
fs = fs_new(NULL, pool);
- SVN_MUTEX__WITH_LOCK(common_pool_lock,
- vtable->open_fs_for_recovery(fs, path, pool,
- common_pool));
+ SVN_ERR(vtable->open_fs_for_recovery(fs, path, common_pool_lock,
+ pool, common_pool));
return svn_error_trace(vtable->recover(fs, cancel_func, cancel_baton,
pool));
}
@@ -680,9 +772,8 @@ svn_fs_create_berkeley(svn_fs_t *fs, const char *path)
SVN_ERR(write_fs_type(path, SVN_FS_TYPE_BDB, fs->pool));
/* Perform the actual creation. */
- SVN_MUTEX__WITH_LOCK(common_pool_lock,
- vtable->create(fs, path, fs->pool, common_pool));
- SVN_ERR(vtable->set_svn_fs_open(fs, svn_fs_open));
+ SVN_ERR(vtable->create(fs, path, common_pool_lock, fs->pool, common_pool));
+ SVN_ERR(vtable->set_svn_fs_open(fs, svn_fs_open2));
return SVN_NO_ERROR;
}
@@ -693,9 +784,8 @@ svn_fs_open_berkeley(svn_fs_t *fs, const char *path)
fs_library_vtable_t *vtable;
SVN_ERR(fs_library_vtable(&vtable, path, fs->pool));
- SVN_MUTEX__WITH_LOCK(common_pool_lock,
- vtable->open_fs(fs, path, fs->pool, common_pool));
- SVN_ERR(vtable->set_svn_fs_open(fs, svn_fs_open));
+ SVN_ERR(vtable->open_fs(fs, path, common_pool_lock, fs->pool, common_pool));
+ SVN_ERR(vtable->set_svn_fs_open(fs, svn_fs_open2));
return SVN_NO_ERROR;
}
@@ -716,8 +806,9 @@ svn_error_t *
svn_fs_hotcopy_berkeley(const char *src_path, const char *dest_path,
svn_boolean_t clean_logs, apr_pool_t *pool)
{
- return svn_error_trace(svn_fs_hotcopy2(src_path, dest_path, clean_logs,
- FALSE, NULL, NULL, pool));
+ return svn_error_trace(svn_fs_hotcopy3(src_path, dest_path, clean_logs,
+ FALSE, NULL, NULL, NULL, NULL,
+ pool));
}
svn_error_t *
@@ -758,16 +849,8 @@ svn_fs_begin_txn2(svn_fs_txn_t **txn_p, svn_fs_t *fs, svn_revnum_t rev,
svn_error_t *
-svn_fs_begin_txn(svn_fs_txn_t **txn_p, svn_fs_t *fs, svn_revnum_t rev,
- apr_pool_t *pool)
-{
- return svn_error_trace(svn_fs_begin_txn2(txn_p, fs, rev, 0, pool));
-}
-
-
-svn_error_t *
svn_fs_commit_txn(const char **conflict_p, svn_revnum_t *new_rev,
- svn_fs_txn_t *txn, apr_pool_t *pool)
+ svn_fs_txn_t *txn, apr_pool_t *pool)
{
svn_error_t *err;
@@ -791,24 +874,9 @@ svn_fs_commit_txn(const char **conflict_p, svn_revnum_t *new_rev,
SVN_ERR(err);
-#ifdef PACK_AFTER_EVERY_COMMIT
- {
- svn_fs_t *fs = txn->fs;
- const char *fs_path = svn_fs_path(fs, pool);
- err = svn_fs_pack(fs_path, NULL, NULL, NULL, NULL, pool);
- if (err && err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE)
- /* Pre-1.6 filesystem. */
- svn_error_clear(err);
- else if (err)
- /* Real error. */
- return svn_error_trace(err);
- }
-#endif
-
return SVN_NO_ERROR;
}
-
svn_error_t *
svn_fs_abort_txn(svn_fs_txn_t *txn, apr_pool_t *pool)
{
@@ -848,23 +916,49 @@ svn_fs_list_transactions(apr_array_header_t **names_p, svn_fs_t *fs,
return svn_error_trace(fs->vtable->list_transactions(names_p, fs, pool));
}
+static svn_boolean_t
+is_internal_txn_prop(const char *name)
+{
+ return strcmp(name, SVN_FS__PROP_TXN_CHECK_LOCKS) == 0 ||
+ strcmp(name, SVN_FS__PROP_TXN_CHECK_OOD) == 0 ||
+ strcmp(name, SVN_FS__PROP_TXN_CLIENT_DATE) == 0;
+}
+
svn_error_t *
svn_fs_txn_prop(svn_string_t **value_p, svn_fs_txn_t *txn,
const char *propname, apr_pool_t *pool)
{
+ if (is_internal_txn_prop(propname))
+ {
+ *value_p = NULL;
+ return SVN_NO_ERROR;
+ }
+
return svn_error_trace(txn->vtable->get_prop(value_p, txn, propname, pool));
}
svn_error_t *
svn_fs_txn_proplist(apr_hash_t **table_p, svn_fs_txn_t *txn, apr_pool_t *pool)
{
- return svn_error_trace(txn->vtable->get_proplist(table_p, txn, pool));
+ SVN_ERR(txn->vtable->get_proplist(table_p, txn, pool));
+
+ /* Don't give away internal transaction properties. */
+ svn_hash_sets(*table_p, SVN_FS__PROP_TXN_CHECK_LOCKS, NULL);
+ svn_hash_sets(*table_p, SVN_FS__PROP_TXN_CHECK_OOD, NULL);
+ svn_hash_sets(*table_p, SVN_FS__PROP_TXN_CLIENT_DATE, NULL);
+
+ return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_change_txn_prop(svn_fs_txn_t *txn, const char *name,
const svn_string_t *value, apr_pool_t *pool)
{
+ if (is_internal_txn_prop(name))
+ return svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
+ _("Attempt to modify internal transaction "
+ "property '%s'"), name);
+
return svn_error_trace(txn->vtable->change_prop(txn, name, value, pool));
}
@@ -872,6 +966,18 @@ svn_error_t *
svn_fs_change_txn_props(svn_fs_txn_t *txn, const apr_array_header_t *props,
apr_pool_t *pool)
{
+ int i;
+
+ for (i = 0; i < props->nelts; ++i)
+ {
+ svn_prop_t *prop = &APR_ARRAY_IDX(props, i, svn_prop_t);
+
+ if (is_internal_txn_prop(prop->name))
+ return svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
+ _("Attempt to modify internal transaction "
+ "property '%s'"), prop->name);
+ }
+
return svn_error_trace(txn->vtable->change_props(txn, props, pool));
}
@@ -940,7 +1046,8 @@ svn_fs_revision_root_revision(svn_fs_root_t *root)
}
svn_error_t *
-svn_fs_paths_changed2(apr_hash_t **changed_paths_p, svn_fs_root_t *root,
+svn_fs_paths_changed2(apr_hash_t **changed_paths_p,
+ svn_fs_root_t *root,
apr_pool_t *pool)
{
return root->vtable->paths_changed(changed_paths_p, root, pool);
@@ -984,11 +1091,21 @@ svn_fs_check_path(svn_node_kind_t *kind_p, svn_fs_root_t *root,
}
svn_error_t *
+svn_fs_node_history2(svn_fs_history_t **history_p, svn_fs_root_t *root,
+ const char *path, apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_trace(root->vtable->node_history(history_p, root, path,
+ result_pool,
+ scratch_pool));
+}
+
+svn_error_t *
svn_fs_node_history(svn_fs_history_t **history_p, svn_fs_root_t *root,
const char *path, apr_pool_t *pool)
{
return svn_error_trace(root->vtable->node_history(history_p, root, path,
- pool));
+ pool, pool));
}
svn_error_t *
@@ -1021,6 +1138,25 @@ svn_fs_node_id(const svn_fs_id_t **id_p, svn_fs_root_t *root,
}
svn_error_t *
+svn_fs_node_relation(svn_fs_node_relation_t *relation,
+ svn_fs_root_t *root_a, const char *path_a,
+ svn_fs_root_t *root_b, const char *path_b,
+ apr_pool_t *scratch_pool)
+{
+ /* Different repository types? */
+ if (root_a->fs != root_b->fs)
+ {
+ *relation = svn_fs_node_unrelated;
+ return SVN_NO_ERROR;
+ }
+
+ return svn_error_trace(root_a->vtable->node_relation(relation,
+ root_a, path_a,
+ root_b, path_b,
+ scratch_pool));
+}
+
+svn_error_t *
svn_fs_node_created_rev(svn_revnum_t *revision, svn_fs_root_t *root,
const char *path, apr_pool_t *pool)
{
@@ -1061,6 +1197,16 @@ svn_fs_node_proplist(apr_hash_t **table_p, svn_fs_root_t *root,
}
svn_error_t *
+svn_fs_node_has_props(svn_boolean_t *has_props,
+ svn_fs_root_t *root,
+ const char *path,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_trace(root->vtable->node_has_props(has_props, root, path,
+ scratch_pool));
+}
+
+svn_error_t *
svn_fs_change_node_prop(svn_fs_root_t *root, const char *path,
const char *name, const svn_string_t *value,
apr_pool_t *pool)
@@ -1070,6 +1216,17 @@ svn_fs_change_node_prop(svn_fs_root_t *root, const char *path,
}
svn_error_t *
+svn_fs_props_different(svn_boolean_t *changed_p, svn_fs_root_t *root1,
+ const char *path1, svn_fs_root_t *root2,
+ const char *path2, apr_pool_t *scratch_pool)
+{
+ return svn_error_trace(root1->vtable->props_changed(changed_p,
+ root1, path1,
+ root2, path2,
+ TRUE, scratch_pool));
+}
+
+svn_error_t *
svn_fs_props_changed(svn_boolean_t *changed_p, svn_fs_root_t *root1,
const char *path1, svn_fs_root_t *root2,
const char *path2, apr_pool_t *pool)
@@ -1077,7 +1234,7 @@ svn_fs_props_changed(svn_boolean_t *changed_p, svn_fs_root_t *root1,
return svn_error_trace(root1->vtable->props_changed(changed_p,
root1, path1,
root2, path2,
- pool));
+ FALSE, pool));
}
svn_error_t *
@@ -1126,6 +1283,30 @@ svn_fs_get_mergeinfo(svn_mergeinfo_catalog_t *catalog,
}
svn_error_t *
+svn_fs__get_mergeinfo_for_path(svn_mergeinfo_t *mergeinfo,
+ svn_fs_root_t *root,
+ const char *path,
+ svn_mergeinfo_inheritance_t inherit,
+ svn_boolean_t adjust_inherited_mergeinfo,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ apr_array_header_t *paths
+ = apr_array_make(scratch_pool, 1, sizeof(const char *));
+ svn_mergeinfo_catalog_t catalog;
+
+ APR_ARRAY_PUSH(paths, const char *) = path;
+
+ SVN_ERR(svn_fs_get_mergeinfo2(&catalog, root, paths,
+ inherit, FALSE /*include_descendants*/,
+ adjust_inherited_mergeinfo,
+ result_pool, scratch_pool));
+ *mergeinfo = svn_hash_gets(catalog, path);
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
svn_fs_merge(const char **conflict_p, svn_fs_root_t *source_root,
const char *source_path, svn_fs_root_t *target_root,
const char *target_path, svn_fs_root_t *ancestor_root,
@@ -1147,6 +1328,19 @@ svn_fs_dir_entries(apr_hash_t **entries_p, svn_fs_root_t *root,
}
svn_error_t *
+svn_fs_dir_optimal_order(apr_array_header_t **ordered_p,
+ svn_fs_root_t *root,
+ apr_hash_t *entries,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_trace(root->vtable->dir_optimal_order(ordered_p, root,
+ entries,
+ result_pool,
+ scratch_pool));
+}
+
+svn_error_t *
svn_fs_make_dir(svn_fs_root_t *root, const char *path, apr_pool_t *pool)
{
SVN_ERR(svn_fs__path_valid(path, pool));
@@ -1302,6 +1496,18 @@ svn_fs_apply_text(svn_stream_t **contents_p, svn_fs_root_t *root,
}
svn_error_t *
+svn_fs_contents_different(svn_boolean_t *changed_p, svn_fs_root_t *root1,
+ const char *path1, svn_fs_root_t *root2,
+ const char *path2, apr_pool_t *scratch_pool)
+{
+ return svn_error_trace(root1->vtable->contents_changed(changed_p,
+ root1, path1,
+ root2, path2,
+ TRUE,
+ scratch_pool));
+}
+
+svn_error_t *
svn_fs_contents_changed(svn_boolean_t *changed_p, svn_fs_root_t *root1,
const char *path1, svn_fs_root_t *root2,
const char *path2, apr_pool_t *pool)
@@ -1309,7 +1515,7 @@ svn_fs_contents_changed(svn_boolean_t *changed_p, svn_fs_root_t *root1,
return svn_error_trace(root1->vtable->contents_changed(changed_p,
root1, path1,
root2, path2,
- pool));
+ FALSE, pool));
}
svn_error_t *
@@ -1319,6 +1525,29 @@ svn_fs_youngest_rev(svn_revnum_t *youngest_p, svn_fs_t *fs, apr_pool_t *pool)
}
svn_error_t *
+svn_fs_info_format(int *fs_format,
+ svn_version_t **supports_version,
+ svn_fs_t *fs,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_trace(fs->vtable->info_format(fs_format, supports_version,
+ fs,
+ result_pool, scratch_pool));
+}
+
+svn_error_t *
+svn_fs_info_config_files(apr_array_header_t **files,
+ svn_fs_t *fs,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_trace(fs->vtable->info_config_files(files, fs,
+ result_pool,
+ scratch_pool));
+}
+
+svn_error_t *
svn_fs_deltify_revision(svn_fs_t *fs, svn_revnum_t revision, apr_pool_t *pool)
{
return svn_error_trace(fs->vtable->deltify(fs, revision, pool));
@@ -1351,14 +1580,6 @@ svn_fs_change_rev_prop2(svn_fs_t *fs, svn_revnum_t rev, const char *name,
}
svn_error_t *
-svn_fs_change_rev_prop(svn_fs_t *fs, svn_revnum_t rev, const char *name,
- const svn_string_t *value, apr_pool_t *pool)
-{
- return svn_error_trace(
- svn_fs_change_rev_prop2(fs, rev, name, NULL, value, pool));
-}
-
-svn_error_t *
svn_fs_get_file_delta_stream(svn_txdelta_stream_t **stream_p,
svn_fs_root_t *source_root,
const char *source_path,
@@ -1398,54 +1619,144 @@ svn_fs_set_uuid(svn_fs_t *fs, const char *uuid, apr_pool_t *pool)
}
svn_error_t *
-svn_fs_lock(svn_lock_t **lock, svn_fs_t *fs, const char *path,
- const char *token, const char *comment,
- svn_boolean_t is_dav_comment, apr_time_t expiration_date,
- svn_revnum_t current_rev, svn_boolean_t steal_lock,
- apr_pool_t *pool)
+svn_fs_lock_many(svn_fs_t *fs,
+ apr_hash_t *targets,
+ const char *comment,
+ svn_boolean_t is_dav_comment,
+ apr_time_t expiration_date,
+ svn_boolean_t steal_lock,
+ svn_fs_lock_callback_t lock_callback,
+ void *lock_baton,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
+ apr_hash_index_t *hi;
+ apr_hash_t *ok_targets = apr_hash_make(scratch_pool);
+ svn_error_t *err, *cb_err = SVN_NO_ERROR;
+
/* Enforce that the comment be xml-escapable. */
if (comment)
- {
- if (! svn_xml_is_xml_safe(comment, strlen(comment)))
- return svn_error_create
- (SVN_ERR_XML_UNESCAPABLE_DATA, NULL,
- _("Lock comment contains illegal characters"));
- }
+ if (! svn_xml_is_xml_safe(comment, strlen(comment)))
+ return svn_error_create(SVN_ERR_XML_UNESCAPABLE_DATA, NULL,
+ _("Lock comment contains illegal characters"));
+
+ if (expiration_date < 0)
+ return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
+ _("Negative expiration date passed to svn_fs_lock"));
/* Enforce that the token be an XML-safe URI. */
- if (token)
+ for (hi = apr_hash_first(scratch_pool, targets); hi; hi = apr_hash_next(hi))
{
- const char *c;
-
- if (strncmp(token, "opaquelocktoken:", 16))
- return svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL,
- _("Lock token URI '%s' has bad scheme; "
- "expected '%s'"),
- token, "opaquelocktoken");
-
- for (c = token; *c; c++)
- if (! svn_ctype_isascii(*c))
- return svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL,
- _("Lock token '%s' is not ASCII "
- "at byte %u"),
- token, (unsigned)(c - token));
-
- /* strlen(token) == c - token. */
- if (! svn_xml_is_xml_safe(token, c - token))
- return svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL,
- _("Lock token URI '%s' is not XML-safe"),
- token);
+ const svn_fs_lock_target_t *target = apr_hash_this_val(hi);
+
+ err = SVN_NO_ERROR;
+ if (target->token)
+ {
+ const char *c;
+
+
+ if (strncmp(target->token, "opaquelocktoken:", 16))
+ err = svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL,
+ _("Lock token URI '%s' has bad scheme; "
+ "expected '%s'"),
+ target->token, "opaquelocktoken");
+
+ if (!err)
+ for (c = target->token; *c && !err; c++)
+ if (! svn_ctype_isascii(*c) || svn_ctype_iscntrl(*c))
+ err = svn_error_createf(
+ SVN_ERR_FS_BAD_LOCK_TOKEN, NULL,
+ _("Lock token '%s' is not ASCII or is a "
+ "control character at byte %u"),
+ target->token,
+ (unsigned)(c - target->token));
+
+ /* strlen(token) == c - token. */
+ if (!err && !svn_xml_is_xml_safe(target->token, c - target->token))
+ err = svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL,
+ _("Lock token URI '%s' is not XML-safe"),
+ target->token);
+ }
+
+ if (err)
+ {
+ if (!cb_err && lock_callback)
+ cb_err = lock_callback(lock_baton, apr_hash_this_key(hi),
+ NULL, err, scratch_pool);
+ svn_error_clear(err);
+ }
+ else
+ svn_hash_sets(ok_targets, apr_hash_this_key(hi), target);
}
- if (expiration_date < 0)
- return svn_error_create
- (SVN_ERR_INCORRECT_PARAMS, NULL,
- _("Negative expiration date passed to svn_fs_lock"));
+ if (!apr_hash_count(ok_targets))
+ return svn_error_trace(cb_err);
+
+ err = fs->vtable->lock(fs, ok_targets, comment, is_dav_comment,
+ expiration_date, steal_lock,
+ lock_callback, lock_baton,
+ result_pool, scratch_pool);
+
+ if (err && cb_err)
+ svn_error_compose(err, cb_err);
+ else if (!err)
+ err = cb_err;
+
+ return svn_error_trace(err);
+}
+
+struct lock_baton_t {
+ const svn_lock_t *lock;
+ svn_error_t *fs_err;
+};
+
+/* Implements svn_fs_lock_callback_t. Used by svn_fs_lock and
+ svn_fs_unlock to record the lock and error from svn_fs_lock_many
+ and svn_fs_unlock_many. */
+static svn_error_t *
+lock_cb(void *lock_baton,
+ const char *path,
+ const svn_lock_t *lock,
+ svn_error_t *fs_err,
+ apr_pool_t *pool)
+{
+ struct lock_baton_t *b = lock_baton;
+
+ b->lock = lock;
+ b->fs_err = svn_error_dup(fs_err);
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_lock(svn_lock_t **lock, svn_fs_t *fs, const char *path,
+ const char *token, const char *comment,
+ svn_boolean_t is_dav_comment, apr_time_t expiration_date,
+ svn_revnum_t current_rev, svn_boolean_t steal_lock,
+ apr_pool_t *pool)
+{
+ apr_hash_t *targets = apr_hash_make(pool);
+ svn_fs_lock_target_t target;
+ svn_error_t *err;
+ struct lock_baton_t baton = {0};
+
+ target.token = token;
+ target.current_rev = current_rev;
+ svn_hash_sets(targets, path, &target);
- return svn_error_trace(fs->vtable->lock(lock, fs, path, token, comment,
- is_dav_comment, expiration_date,
- current_rev, steal_lock, pool));
+ err = svn_fs_lock_many(fs, targets, comment, is_dav_comment,
+ expiration_date, steal_lock, lock_cb, &baton,
+ pool, pool);
+
+ if (baton.lock)
+ *lock = (svn_lock_t*)baton.lock;
+
+ if (err && baton.fs_err)
+ svn_error_compose(err, baton.fs_err);
+ else if (!err)
+ err = baton.fs_err;
+
+ return svn_error_trace(err);
}
svn_error_t *
@@ -1454,12 +1765,62 @@ svn_fs_generate_lock_token(const char **token, svn_fs_t *fs, apr_pool_t *pool)
return svn_error_trace(fs->vtable->generate_lock_token(token, fs, pool));
}
+svn_fs_lock_target_t *
+svn_fs_lock_target_create(const char *token,
+ svn_revnum_t current_rev,
+ apr_pool_t *result_pool)
+{
+ svn_fs_lock_target_t *target = apr_palloc(result_pool,
+ sizeof(svn_fs_lock_target_t));
+
+ target->token = token;
+ target->current_rev = current_rev;
+
+ return target;
+}
+
+void
+svn_fs_lock_target_set_token(svn_fs_lock_target_t *target,
+ const char *token)
+{
+ target->token = token;
+}
+
+svn_error_t *
+svn_fs_unlock_many(svn_fs_t *fs,
+ apr_hash_t *targets,
+ svn_boolean_t break_lock,
+ svn_fs_lock_callback_t lock_callback,
+ void *lock_baton,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_trace(fs->vtable->unlock(fs, targets, break_lock,
+ lock_callback, lock_baton,
+ result_pool, scratch_pool));
+}
+
svn_error_t *
svn_fs_unlock(svn_fs_t *fs, const char *path, const char *token,
svn_boolean_t break_lock, apr_pool_t *pool)
{
- return svn_error_trace(fs->vtable->unlock(fs, path, token, break_lock,
- pool));
+ apr_hash_t *targets = apr_hash_make(pool);
+ svn_error_t *err;
+ struct lock_baton_t baton = {0};
+
+ if (!token)
+ token = "";
+ svn_hash_sets(targets, path, token);
+
+ err = svn_fs_unlock_many(fs, targets, break_lock, lock_cb, &baton,
+ pool, pool);
+
+ if (err && baton.fs_err)
+ svn_error_compose(err, baton.fs_err);
+ else if (!err)
+ err = baton.fs_err;
+
+ return svn_error_trace(err);
}
svn_error_t *
@@ -1483,26 +1844,26 @@ svn_fs_get_locks2(svn_fs_t *fs, const char *path, svn_depth_t depth,
get_locks_baton, pool));
}
+
+/* --- History functions --- */
+
svn_error_t *
-svn_fs_get_locks(svn_fs_t *fs, const char *path,
- svn_fs_get_locks_callback_t get_locks_func,
- void *get_locks_baton, apr_pool_t *pool)
+svn_fs_history_prev2(svn_fs_history_t **prev_history_p,
+ svn_fs_history_t *history, svn_boolean_t cross_copies,
+ apr_pool_t *result_pool, apr_pool_t *scratch_pool)
{
- return svn_error_trace(svn_fs_get_locks2(fs, path, svn_depth_infinity,
- get_locks_func, get_locks_baton,
- pool));
+ return svn_error_trace(history->vtable->prev(prev_history_p, history,
+ cross_copies, result_pool,
+ scratch_pool));
}
-
-/* --- History functions --- */
-
svn_error_t *
svn_fs_history_prev(svn_fs_history_t **prev_history_p,
svn_fs_history_t *history, svn_boolean_t cross_copies,
apr_pool_t *pool)
{
return svn_error_trace(history->vtable->prev(prev_history_p, history,
- cross_copies, pool));
+ cross_copies, pool, pool));
}
svn_error_t *
@@ -1540,20 +1901,28 @@ svn_fs_unparse_id(const svn_fs_id_t *id, apr_pool_t *pool)
svn_boolean_t
svn_fs_check_related(const svn_fs_id_t *a, const svn_fs_id_t *b)
{
- return (a->vtable->compare(a, b) != -1);
+ return (a->vtable->compare(a, b) != svn_fs_node_unrelated);
}
int
svn_fs_compare_ids(const svn_fs_id_t *a, const svn_fs_id_t *b)
{
- return a->vtable->compare(a, b);
+ switch (a->vtable->compare(a, b))
+ {
+ case svn_fs_node_unchanged:
+ return 0;
+ case svn_fs_node_common_ancestor:
+ return 1;
+ default:
+ return -1;
+ }
}
svn_error_t *
svn_fs_print_modules(svn_stringbuf_t *output,
apr_pool_t *pool)
{
- const struct fs_type_defn *defn = fs_modules;
+ struct fs_type_defn *defn = fs_modules;
fs_library_vtable_t *vtable;
apr_pool_t *iterpool = svn_pool_create(pool);
@@ -1602,3 +1971,43 @@ svn_fs_version(void)
{
SVN_VERSION_BODY;
}
+
+
+/** info **/
+svn_error_t *
+svn_fs_info(const svn_fs_info_placeholder_t **info_p,
+ svn_fs_t *fs,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ if (fs->vtable->info_fsap)
+ {
+ SVN_ERR(fs->vtable->info_fsap((const void **)info_p, fs,
+ result_pool, scratch_pool));
+ }
+ else
+ {
+ svn_fs_info_placeholder_t *info = apr_palloc(result_pool, sizeof(*info));
+ /* ### Ask the disk(!), since svn_fs_t doesn't cache the answer. */
+ SVN_ERR(svn_fs_type(&info->fs_type, fs->path, result_pool));
+ *info_p = info;
+ }
+ return SVN_NO_ERROR;
+}
+
+void *
+svn_fs_info_dup(const void *info_void,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const svn_fs_info_placeholder_t *info = info_void;
+ fs_library_vtable_t *vtable;
+
+ SVN_ERR(get_library_vtable(&vtable, info->fs_type, scratch_pool));
+
+ if (vtable->info_fsap_dup)
+ return vtable->info_fsap_dup(info_void, result_pool);
+ else
+ return apr_pmemdup(result_pool, info, sizeof(*info));
+}
+